Skip to content

Commit 9bf1b5b

Browse files
committed
Try to work around deserialization issues with Gson.
All deserialized models have listeners that need to be initialized and registered to the main ParameterSweepModel. But when deserializing Gson, the constructor of the base class is not called, and the listeners are not re-registered. We try to work around this in a better way: - The listeners field is initialized in the class definition, not in the constructor. But this does not work all the time either. For a reason that completely escapes me, sometimes an instance will not have this field initialized. Weird. - A default visibility method is called by the Gson deserialization logic to re-register the listeners to the main model. - The param models have also an initialize() method that recreates the listeners. - Special case for CondaEnvParamSweepModel: the env list is cleared after deserialization and replaced by the env list discovered at runtime. - Also: all RangeType enums have been renamed according to what is their mother param type for clarity.
1 parent 076ccf7 commit 9bf1b5b

24 files changed

Lines changed: 211 additions & 187 deletions

src/main/java/fiji/plugin/trackmate/helper/model/AbstractSweepModelBase.java

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
* it under the terms of the GNU General Public License as
99
* published by the Free Software Foundation, either version 3 of the
1010
* License, or (at your option) any later version.
11-
*
11+
*
1212
* This program is distributed in the hope that it will be useful,
1313
* but WITHOUT ANY WARRANTY; without even the implied warranty of
1414
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1515
* GNU General Public License for more details.
16-
*
16+
*
1717
* You should have received a copy of the GNU General Public
1818
* License along with this program. If not, see
1919
* <http://www.gnu.org/licenses/gpl-3.0.html>.
@@ -38,7 +38,7 @@ public interface ModelListener
3838
public void modelChanged();
3939
}
4040

41-
private transient Listeners.List< ModelListener > modelListeners;
41+
private final transient Listeners.List< ModelListener > modelListeners = new Listeners.SynchronizedList<>();
4242

4343
protected final String name;
4444

@@ -68,16 +68,6 @@ public String getName()
6868

6969
public final Listeners.List< ModelListener > listeners()
7070
{
71-
if ( modelListeners == null )
72-
{
73-
/*
74-
* Work around the listeners field being null after deserialization.
75-
* We also need to register again the sub-models.
76-
*/
77-
this.modelListeners = new Listeners.SynchronizedList<>();
78-
for ( final AbstractParamSweepModel< ? > model : models.values() )
79-
model.listeners().add( () -> notifyListeners() );
80-
}
8171
return modelListeners;
8272
}
8373

src/main/java/fiji/plugin/trackmate/helper/model/ParameterSweepModel.java

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
* it under the terms of the GNU General Public License as
99
* published by the Free Software Foundation, either version 3 of the
1010
* License, or (at your option) any later version.
11-
*
11+
*
1212
* This program is distributed in the hope that it will be useful,
1313
* but WITHOUT ANY WARRANTY; without even the implied warranty of
1414
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1515
* GNU General Public License for more details.
16-
*
16+
*
1717
* You should have received a copy of the GNU General Public
1818
* License along with this program. If not, see
1919
* <http://www.gnu.org/licenses/gpl-3.0.html>.
@@ -48,7 +48,7 @@
4848
public class ParameterSweepModel
4949
{
5050

51-
private final transient Listeners.List< ModelListener > modelListeners;
51+
private final transient Listeners.List< ModelListener > modelListeners = new Listeners.SynchronizedList<>();
5252

5353
private final Map< String, DetectorSweepModel > detectorModels;
5454

@@ -62,8 +62,6 @@ public class ParameterSweepModel
6262

6363
public ParameterSweepModel()
6464
{
65-
modelListeners = new Listeners.SynchronizedList<>();
66-
6765
// Auto-detect detectors & trackers.
6866
detectorModels = autoDetect( DetectorSweepModel.class );
6967
trackerModels = autoDetect( TrackerSweepModel.class );
@@ -78,18 +76,34 @@ public ParameterSweepModel()
7876
this.spotFilterModels = new ArrayList<>();
7977
this.trackFilterModels = new ArrayList<>();
8078

81-
registerListeners();
82-
}
83-
84-
public void registerListeners()
85-
{
86-
// Forward component changes to listeners.
79+
// Register models.
8780
detectorModels().forEach( model -> model.listeners().add( () -> notifyListeners() ) );
8881
trackerModels().forEach( model -> model.listeners().add( () -> notifyListeners() ) );
8982
spotFilterModels().forEach( model -> model.listeners().add( () -> notifyListeners() ) );
9083
trackFilterModels().forEach( model -> model.listeners().add( () -> notifyListeners() ) );
9184
}
9285

86+
/**
87+
* This is used <b>only</b> for deserizalisation, to re-register listeners
88+
* in the model components of the main models.
89+
*/
90+
void reRegisterListeners()
91+
{
92+
final ModelListener notifier = () -> notifyListeners();
93+
reRegisterListeners( detectorModels.values(), notifier );
94+
reRegisterListeners( trackerModels.values(), notifier );
95+
reRegisterListeners( spotFilterModels, notifier );
96+
reRegisterListeners( spotFilterModels, notifier );
97+
}
98+
99+
private void reRegisterListeners( final Collection< ? extends AbstractSweepModelBase > models, final ModelListener notifier )
100+
{
101+
models.forEach( m -> {
102+
m.listeners().add( notifier );
103+
m.models.values().forEach( sm -> sm.listeners().add( notifier ) );
104+
} );
105+
}
106+
93107
public Collection< DetectorSweepModel > detectorModels()
94108
{
95109
return detectorModels.values();
@@ -179,7 +193,7 @@ public List< TrackerSweepModel > getActiveTracker()
179193
/**
180194
* Returns the count of the different settings that will be generated from
181195
* this model.
182-
*
196+
*
183197
* @return the count of settings.
184198
*/
185199
public int count()
@@ -190,7 +204,7 @@ public int count()
190204
/**
191205
* Returns the count of the different tracker settings that will be
192206
* generated from this model.
193-
*
207+
*
194208
* @return the count of settings.
195209
*/
196210
public int countTrackerSettings()
@@ -213,7 +227,7 @@ public int countTrackerSettings()
213227
/**
214228
* Returns the count of the different detector settings that will be
215229
* generated from this model.
216-
*
230+
*
217231
* @return the count of settings.
218232
*/
219233
public int countDetectorSettings()
@@ -236,7 +250,7 @@ public int countDetectorSettings()
236250
/**
237251
* Returns the count of the different spot filter settings that will be
238252
* generated from this model.
239-
*
253+
*
240254
* @return the count of settings.
241255
*/
242256
public int countSpotFilterSettings()
@@ -260,7 +274,7 @@ public int countSpotFilterSettings()
260274
/**
261275
* Returns the count of the different track filter settings that will be
262276
* generated from this model.
263-
*
277+
*
264278
* @return the count of settings.
265279
*/
266280
public int countTrackFilterSettings()

src/main/java/fiji/plugin/trackmate/helper/model/ParameterSweepModelIO.java

Lines changed: 5 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@
3434

3535
import javax.swing.JOptionPane;
3636

37-
import com.google.gson.ExclusionStrategy;
38-
import com.google.gson.FieldAttributes;
3937
import com.google.gson.Gson;
4038
import com.google.gson.GsonBuilder;
4139
import com.google.gson.JsonArray;
@@ -51,9 +49,9 @@
5149
import fiji.plugin.trackmate.detection.SpotDetectorFactoryBase;
5250
import fiji.plugin.trackmate.gui.Icons;
5351
import fiji.plugin.trackmate.helper.model.detector.DetectorSweepModel;
54-
import fiji.plugin.trackmate.helper.model.parameter.AbstractArrayParamSweepModel.RangeType;
52+
import fiji.plugin.trackmate.helper.model.parameter.AbstractArrayParamSweepModel.ArrayRangeType;
5553
import fiji.plugin.trackmate.helper.model.parameter.AbstractParamSweepModel;
56-
import fiji.plugin.trackmate.helper.model.parameter.CondaEnvParamSweepModel;
54+
import fiji.plugin.trackmate.helper.model.parameter.AbstractParamSweepModelIO;
5755
import fiji.plugin.trackmate.helper.model.parameter.EnumParamSweepModel;
5856
import fiji.plugin.trackmate.helper.model.tracker.TrackerSweepModel;
5957
import fiji.plugin.trackmate.providers.DetectorProvider;
@@ -158,11 +156,10 @@ public static ParameterSweepModel readFromDefault()
158156
private static Gson getGson()
159157
{
160158
final GsonBuilder builder = new GsonBuilder()
161-
.addDeserializationExclusionStrategy( new CustomExclusionStrategy() )
162159
.registerTypeAdapter( EnumParamSweepModel.class, new EnumParamSweepModelAdapter<>() )
163160
.registerTypeAdapter( SpotDetectorFactoryBase.class, new SpotDetectorFactoryBaseAdapter() )
164161
.registerTypeAdapter( SpotTrackerFactory.class, new SpotTrackerFactoryAdapter() )
165-
.registerTypeAdapter( AbstractParamSweepModel.class, new AbstractParamSweepModelAdapter() )
162+
.registerTypeAdapter( AbstractParamSweepModel.class, new AbstractParamSweepModelIO() )
166163
.registerTypeAdapter( DetectorSweepModel.class, new DetectorSweepModelAdapter() )
167164
.registerTypeAdapter( TrackerSweepModel.class, new TrackerSweepModelAdapter() )
168165
.registerTypeAdapter( Class.class, new ClassTypeAdapter() );
@@ -177,55 +174,10 @@ public static String toJson( final ParameterSweepModel model )
177174
public static ParameterSweepModel fromJson( final String str )
178175
{
179176
final ParameterSweepModel model = getGson().fromJson( str, ParameterSweepModel.class );
180-
model.registerListeners();
177+
model.reRegisterListeners();
181178
return model;
182179
}
183180

184-
private static class CustomExclusionStrategy implements ExclusionStrategy
185-
{
186-
@Override
187-
public boolean shouldSkipField( final FieldAttributes f )
188-
{
189-
return f.getDeclaringClass() == CondaEnvParamSweepModel.class && f.getName().equals( "allValues" );
190-
}
191-
192-
@Override
193-
public boolean shouldSkipClass( final Class< ? > clazz )
194-
{
195-
return false;
196-
}
197-
}
198-
199-
private static class AbstractParamSweepModelAdapter implements JsonSerializer< AbstractParamSweepModel< ? > >, JsonDeserializer< AbstractParamSweepModel< ? > >
200-
{
201-
202-
@Override
203-
public AbstractParamSweepModel< ? > deserialize( final JsonElement json, final Type typeOfT, final JsonDeserializationContext context ) throws JsonParseException
204-
{
205-
final JsonObject jsonObject = json.getAsJsonObject();
206-
final String type = jsonObject.get( "type" ).getAsString();
207-
final JsonElement element = jsonObject.get( "properties" );
208-
209-
try
210-
{
211-
return context.deserialize( element, Class.forName( "fiji.plugin.trackmate.helper.model.parameter." + type ) );
212-
}
213-
catch ( final ClassNotFoundException cnfe )
214-
{
215-
throw new JsonParseException( "Unknown element type: " + type, cnfe );
216-
}
217-
}
218-
219-
@Override
220-
public JsonElement serialize( final AbstractParamSweepModel< ? > src, final Type typeOfSrc, final JsonSerializationContext context )
221-
{
222-
final JsonObject result = new JsonObject();
223-
result.add( "type", new JsonPrimitive( src.getClass().getSimpleName() ) );
224-
result.add( "properties", context.serialize( src, src.getClass() ) );
225-
return result;
226-
}
227-
}
228-
229181
private static class DetectorSweepModelAdapter implements JsonSerializer< DetectorSweepModel >, JsonDeserializer< DetectorSweepModel >
230182
{
231183

@@ -457,7 +409,7 @@ public EnumParamSweepModel< T > deserialize( final JsonElement json, final Type
457409
final EnumParamSweepModel< T > model = new EnumParamSweepModel<>( enumClass );
458410
model.paramName( obj.get( "paramName" ).getAsString() );
459411
model.fixedValue( Enum.valueOf( enumClass, obj.get( "fixedValue" ).getAsString() ) );
460-
model.rangeType( Enum.valueOf( RangeType.class, obj.get( "rangeType" ).getAsString() ) );
412+
model.rangeType( Enum.valueOf( ArrayRangeType.class, obj.get( "rangeType" ).getAsString() ) );
461413
final JsonArray arr = obj.get( "set" ).getAsJsonArray();
462414
for ( final JsonElement el : arr )
463415
model.addValue( Enum.valueOf( enumClass, el.getAsString() ) );

src/main/java/fiji/plugin/trackmate/helper/model/detector/CellposeOpt.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
* it under the terms of the GNU General Public License as
99
* published by the Free Software Foundation, either version 3 of the
1010
* License, or (at your option) any later version.
11-
*
11+
*
1212
* This program is distributed in the hope that it will be useful,
1313
* but WITHOUT ANY WARRANTY; without even the implied warranty of
1414
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1515
* GNU General Public License for more details.
16-
*
16+
*
1717
* You should have received a copy of the GNU General Public
1818
* License along with this program. If not, see
1919
* <http://www.gnu.org/licenses/gpl-3.0.html>.
@@ -31,8 +31,10 @@
3131
import fiji.plugin.trackmate.detection.DetectorKeys;
3232
import fiji.plugin.trackmate.detection.SpotDetectorFactoryBase;
3333
import fiji.plugin.trackmate.detection.ThresholdDetectorFactory;
34+
import fiji.plugin.trackmate.helper.model.parameter.AbstractArrayParamSweepModel.ArrayRangeType;
3435
import fiji.plugin.trackmate.helper.model.parameter.AbstractParamSweepModel;
3536
import fiji.plugin.trackmate.helper.model.parameter.BooleanParamSweepModel;
37+
import fiji.plugin.trackmate.helper.model.parameter.BooleanParamSweepModel.BooleanRangeType;
3638
import fiji.plugin.trackmate.helper.model.parameter.DoubleParamSweepModel;
3739
import fiji.plugin.trackmate.helper.model.parameter.EnumParamSweepModel;
3840
import fiji.plugin.trackmate.helper.model.parameter.IntParamSweepModel;
@@ -53,7 +55,7 @@ private CellposeOpt()
5355
.add( System.getProperty( "user.home" ) );
5456
final EnumParamSweepModel< PretrainedModelCellpose > cellposeModel = new EnumParamSweepModel<>( PretrainedModelCellpose.class )
5557
.paramName( "Cellpose model" )
56-
.rangeType( fiji.plugin.trackmate.helper.model.parameter.ArrayParamSweepModel.RangeType.FIXED )
58+
.rangeType( ArrayRangeType.FIXED )
5759
.addValue( PretrainedModelCellpose.CYTO )
5860
.addValue( PretrainedModelCellpose.CYTO2 )
5961
.fixedValue( PretrainedModelCellpose.CYTO );
@@ -79,11 +81,11 @@ private CellposeOpt()
7981
.max( 50. );
8082
final BooleanParamSweepModel useGPU = new BooleanParamSweepModel()
8183
.paramName( "Use GPU" )
82-
.rangeType( fiji.plugin.trackmate.helper.model.parameter.BooleanParamSweepModel.RangeType.FIXED )
84+
.rangeType( BooleanRangeType.FIXED )
8385
.fixedValue( true );
8486
final BooleanParamSweepModel simplifyContours = new BooleanParamSweepModel()
8587
.paramName( "Simplify contours" )
86-
.rangeType( fiji.plugin.trackmate.helper.model.parameter.BooleanParamSweepModel.RangeType.FIXED )
88+
.rangeType( BooleanRangeType.FIXED )
8789
.fixedValue( true );
8890

8991
final Map< String, AbstractParamSweepModel< ? > > models = new LinkedHashMap<>();

src/main/java/fiji/plugin/trackmate/helper/model/detector/DogDetectorModel.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
* it under the terms of the GNU General Public License as
99
* published by the Free Software Foundation, either version 3 of the
1010
* License, or (at your option) any later version.
11-
*
11+
*
1212
* This program is distributed in the hope that it will be useful,
1313
* but WITHOUT ANY WARRANTY; without even the implied warranty of
1414
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1515
* GNU General Public License for more details.
16-
*
16+
*
1717
* You should have received a copy of the GNU General Public
1818
* License along with this program. If not, see
1919
* <http://www.gnu.org/licenses/gpl-3.0.html>.
@@ -31,6 +31,7 @@
3131
import fiji.plugin.trackmate.detection.DogDetectorFactory;
3232
import fiji.plugin.trackmate.helper.model.parameter.AbstractParamSweepModel;
3333
import fiji.plugin.trackmate.helper.model.parameter.BooleanParamSweepModel;
34+
import fiji.plugin.trackmate.helper.model.parameter.BooleanParamSweepModel.BooleanRangeType;
3435
import fiji.plugin.trackmate.helper.model.parameter.DoubleParamSweepModel;
3536
import fiji.plugin.trackmate.helper.model.parameter.NumberParamSweepModel.RangeType;
3637

@@ -58,11 +59,11 @@ public DogDetectorModel()
5859
.nSteps( 3 );
5960
final BooleanParamSweepModel subpixelLocalization = new BooleanParamSweepModel()
6061
.paramName( "Sub-pixel localization" )
61-
.rangeType( BooleanParamSweepModel.RangeType.FIXED )
62+
.rangeType( BooleanRangeType.FIXED )
6263
.fixedValue( true );
6364
final BooleanParamSweepModel useMedian = new BooleanParamSweepModel()
6465
.paramName( "Median pre-processing" )
65-
.rangeType( BooleanParamSweepModel.RangeType.FIXED )
66+
.rangeType( BooleanRangeType.FIXED )
6667
.fixedValue( false );
6768

6869
final Map< String, AbstractParamSweepModel< ? > > models = new LinkedHashMap<>();

src/main/java/fiji/plugin/trackmate/helper/model/detector/HessianDetectorModel.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
* it under the terms of the GNU General Public License as
99
* published by the Free Software Foundation, either version 3 of the
1010
* License, or (at your option) any later version.
11-
*
11+
*
1212
* This program is distributed in the hope that it will be useful,
1313
* but WITHOUT ANY WARRANTY; without even the implied warranty of
1414
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1515
* GNU General Public License for more details.
16-
*
16+
*
1717
* You should have received a copy of the GNU General Public
1818
* License along with this program. If not, see
1919
* <http://www.gnu.org/licenses/gpl-3.0.html>.
@@ -31,6 +31,7 @@
3131
import fiji.plugin.trackmate.detection.HessianDetectorFactory;
3232
import fiji.plugin.trackmate.helper.model.parameter.AbstractParamSweepModel;
3333
import fiji.plugin.trackmate.helper.model.parameter.BooleanParamSweepModel;
34+
import fiji.plugin.trackmate.helper.model.parameter.BooleanParamSweepModel.BooleanRangeType;
3435
import fiji.plugin.trackmate.helper.model.parameter.DoubleParamSweepModel;
3536
import fiji.plugin.trackmate.helper.model.parameter.NumberParamSweepModel.RangeType;
3637

@@ -63,11 +64,11 @@ public HessianDetectorModel( )
6364
.nSteps( 3 );
6465
final BooleanParamSweepModel normalizeQuality = new BooleanParamSweepModel()
6566
.paramName( "Normalize quality" )
66-
.rangeType( BooleanParamSweepModel.RangeType.FIXED )
67+
.rangeType( BooleanRangeType.FIXED )
6768
.fixedValue( true );
6869
final BooleanParamSweepModel subpixelLocalization = new BooleanParamSweepModel()
6970
.paramName( "Sub-pixel localization" )
70-
.rangeType( BooleanParamSweepModel.RangeType.FIXED )
71+
.rangeType( BooleanRangeType.FIXED )
7172
.fixedValue( true );
7273

7374
final Map< String, AbstractParamSweepModel< ? > > models = new LinkedHashMap<>();

0 commit comments

Comments
 (0)