Skip to content

Commit 8e11e2e

Browse files
committed
Merge pull request #125 from scijava/convert-refining
Adds more default implementations to the abstract Converter layer, simplifying the Converter implementation process. Adds a NullConverter to encapsulate null translation logic.
2 parents ca1aa0d + 9284480 commit 8e11e2e

File tree

7 files changed

+353
-136
lines changed

7 files changed

+353
-136
lines changed

src/main/java/org/scijava/convert/AbstractConverter.java

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@
3131

3232
package org.scijava.convert;
3333

34+
import java.lang.reflect.Type;
3435
import java.util.Collection;
3536

3637
import org.scijava.plugin.AbstractHandlerPlugin;
38+
import org.scijava.util.GenericUtils;
3739

3840
/**
3941
* Abstract superclass for {@link Converter} plugins. Performs appropriate
@@ -59,27 +61,49 @@ public abstract class AbstractConverter<I, O> extends
5961

6062
// -- ConversionHandler methods --
6163

64+
@SuppressWarnings("deprecation")
6265
@Override
6366
public boolean canConvert(final ConversionRequest request) {
64-
final Class<?> src = request.sourceClass();
65-
if (src == null) return true;
67+
Object src = request.sourceObject();
68+
if (src == null) {
69+
Class<?> srcClass = request.sourceClass();
70+
if (request.destType() != null) return canConvert(srcClass, request.destType());
71+
return canConvert(srcClass, request.destClass());
72+
}
6673

67-
if (request.destClass() != null) return canConvert(src, request.destClass());
6874
if (request.destType() != null) return canConvert(src, request.destType());
75+
return canConvert(src, request.destClass());
76+
}
6977

70-
return false;
78+
@Override
79+
public boolean canConvert(final Object src, final Type dest) {
80+
if (src == null) return false;
81+
final Class<?> srcClass = src.getClass();
82+
return canConvert(srcClass, dest);
7183
}
7284

85+
@SuppressWarnings("deprecation")
7386
@Override
74-
public Object convert(final ConversionRequest request) {
75-
if (request.sourceObject() != null) {
76-
if (request.destClass() != null) return convert(request.sourceObject(),
77-
request.destClass());
87+
public boolean canConvert(final Object src, final Class<?> dest) {
88+
if (src == null) return false;
89+
final Class<?> srcClass = src.getClass();
7890

79-
if (request.destType() != null) return convert(request.sourceObject(),
80-
request.destType());
91+
return canConvert(srcClass, dest);
92+
}
93+
94+
@Override
95+
public Object convert(final Object src, final Type dest) {
96+
final Class<?> destClass = GenericUtils.getClass(dest);
97+
return convert(src, destClass);
98+
}
99+
100+
@Override
101+
public Object convert(final ConversionRequest request) {
102+
if (request.destType() != null) {
103+
return convert(request.sourceObject(), request.destType());
81104
}
82-
return null;
105+
106+
return convert(request.sourceObject(), request.destClass());
83107
}
84108

85109
@Override
@@ -98,4 +122,13 @@ public boolean supports(final ConversionRequest request) {
98122
public Class<ConversionRequest> getType() {
99123
return ConversionRequest.class;
100124
}
125+
126+
// -- Deprecated API --
127+
128+
@Override
129+
@Deprecated
130+
public boolean canConvert(final Class<?> src, final Type dest) {
131+
final Class<?> destClass = GenericUtils.getClass(dest);
132+
return canConvert(src, destClass);
133+
}
101134
}

src/main/java/org/scijava/convert/ConvertService.java

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,36 +71,46 @@ public interface ConvertService extends
7171
/**
7272
* @see #getHandler(ConversionRequest)
7373
*/
74-
Converter<?, ?> getHandler(Class<?> src, Class<?> dest);
74+
Converter<?, ?> getHandler(Object src, Type dest);
7575

7676
/**
77-
* @see #getHandler(ConversionRequest)
77+
* @see #supports(ConversionRequest)
7878
*/
79-
Converter<?, ?> getHandler(Object src, Type dest);
79+
boolean supports(Object src, Class<?> dest);
8080

8181
/**
82-
* @see #getHandler(ConversionRequest)
82+
* @see #supports(ConversionRequest)
8383
*/
84-
Converter<?, ?> getHandler(Class<?> src, Type dest);
84+
boolean supports(Object src, Type dest);
85+
86+
// -- Deprecated API --
8587

8688
/**
87-
* @see #supports(ConversionRequest)
89+
* @see #getHandler(ConversionRequest)
90+
* @deprecated Use {@link #getHandler(Object, Class)}
8891
*/
89-
boolean supports(Object src, Class<?> dest);
92+
@Deprecated
93+
Converter<?, ?> getHandler(Class<?> src, Class<?> dest);
9094

9195
/**
92-
* @see #supports(ConversionRequest)
96+
* @see #getHandler(ConversionRequest)
97+
* @deprecated Use {@link #getHandler(Object, Type)}
9398
*/
94-
boolean supports(Class<?> src, Class<?> dest);
99+
@Deprecated
100+
Converter<?, ?> getHandler(Class<?> src, Type dest);
95101

96102
/**
97103
* @see #supports(ConversionRequest)
104+
* @deprecated Use {@link #supports(Object, Class)}
98105
*/
99-
boolean supports(Object src, Type dest);
106+
@Deprecated
107+
boolean supports(Class<?> src, Class<?> dest);
100108

101109
/**
102110
* @see #supports(ConversionRequest)
111+
* @deprecated Use {@link #supports(Object, Type)}
103112
*/
113+
@Deprecated
104114
boolean supports(Class<?> src, Type dest);
105115

106116
Collection<Object> getCompatibleInputs(Class<?> dest);

src/main/java/org/scijava/convert/Converter.java

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -61,22 +61,6 @@ public interface Converter<I, O> extends HandlerPlugin<ConversionRequest>
6161
*/
6262
boolean canConvert(ConversionRequest request);
6363

64-
/**
65-
* Checks whether objects of the given class can be converted to the specified
66-
* type.
67-
*
68-
* @see #convert(Object, Type)
69-
*/
70-
boolean canConvert(Class<?> src, Type dest);
71-
72-
/**
73-
* Checks whether objects of the given class can be converted to the specified
74-
* type.
75-
*
76-
* @see #convert(Object, Class)
77-
*/
78-
boolean canConvert(Class<?> src, Class<?> dest);
79-
8064
/**
8165
* Checks whether the given object's type can be converted to the specified
8266
* type.
@@ -189,4 +173,26 @@ public interface Converter<I, O> extends HandlerPlugin<ConversionRequest>
189173
* @return The base {@code Class} this {@code Converter} accepts as input.
190174
*/
191175
Class<I> getInputType();
176+
177+
// -- Deprecated API --
178+
179+
/**
180+
* Checks whether objects of the given class can be converted to the specified
181+
* type.
182+
*
183+
* @see #convert(Object, Type)
184+
* @deprecated Use {@link #canConvert(Object, Type)}
185+
*/
186+
@Deprecated
187+
boolean canConvert(Class<?> src, Type dest);
188+
189+
/**
190+
* Checks whether objects of the given class can be converted to the specified
191+
* type.
192+
*
193+
* @see #convert(Object, Class)
194+
* @deprecated Use {@link #canConvert(Object, Class)}
195+
*/
196+
@Deprecated
197+
boolean canConvert(Class<?> src, Class<?> dest);
192198
}

src/main/java/org/scijava/convert/DefaultConverter.java

Lines changed: 62 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -59,84 +59,6 @@ public class DefaultConverter extends AbstractConverter<Object, Object> {
5959

6060
// -- ConversionHandler methods --
6161

62-
@Override
63-
public boolean canConvert(final Class<?> src, final Type dest) {
64-
// NB: Regardless of whether the destination type is an array or collection,
65-
// we still want to cast directly if doing so is possible. But note that in
66-
// general, this check does not detect cases of incompatible generic
67-
// parameter types. If this limitation becomes a problem in the future we
68-
// can extend the logic here to provide additional signatures of canCast
69-
// which operate on Types in general rather than only Classes. However, the
70-
// logic could become complex very quickly in various subclassing cases,
71-
// generic parameters resolved vs. propagated, etc.
72-
final Class<?> c = GenericUtils.getClass(dest);
73-
if (c != null && ConversionUtils.canCast(src, c)) return true;
74-
75-
// Handle array types, including generic array types.
76-
if (isArray(dest)) return true;
77-
78-
// Handle parameterized collection types.
79-
if (dest instanceof ParameterizedType && isCollection(dest)) {
80-
return createCollection(GenericUtils.getClass(dest)) != null;
81-
}
82-
83-
// This wasn't a collection or array, so convert it as a single element.
84-
return canConvert(src, GenericUtils.getClass(dest));
85-
}
86-
87-
@Override
88-
public boolean canConvert(final Class<?> src, final Class<?> dest) {
89-
// ensure type is well-behaved, rather than a primitive type
90-
final Class<?> saneDest = ConversionUtils.getNonprimitiveType(dest);
91-
92-
// OK if the existing object can be casted
93-
if (ConversionUtils.canCast(src, saneDest)) return true;
94-
95-
// OK for numerical conversions
96-
if (ConversionUtils.canCast(ConversionUtils.getNonprimitiveType(src),
97-
Number.class) &&
98-
(ClassUtils.isByte(dest) || ClassUtils.isDouble(dest) ||
99-
ClassUtils.isFloat(dest) || ClassUtils.isInteger(dest) ||
100-
ClassUtils.isLong(dest) || ClassUtils.isShort(dest)))
101-
{
102-
return true;
103-
}
104-
105-
// OK if string
106-
if (saneDest == String.class) return true;
107-
108-
if (ConversionUtils.canCast(src, String.class)) {
109-
// OK if source type is string and destination type is character
110-
// (in this case, the first character of the string would be used)
111-
if (saneDest == Character.class) return true;
112-
113-
// OK if source type is string and destination type is an enum
114-
if (dest.isEnum()) return true;
115-
}
116-
117-
// OK if appropriate wrapper constructor exists
118-
try {
119-
return getConstructor(saneDest, src) != null;
120-
}
121-
catch (final Exception exc) {
122-
// TODO: Best not to catch blanket Exceptions here.
123-
// no known way to convert
124-
return false;
125-
}
126-
}
127-
128-
@Override
129-
public boolean canConvert(final Object src, final Type dest) {
130-
if (src == null) return true;
131-
return canConvert(src.getClass(), dest);
132-
}
133-
134-
@Override
135-
public boolean canConvert(final Object src, final Class<?> dest) {
136-
if (src == null) return true;
137-
return canConvert(src.getClass(), dest);
138-
}
139-
14062
@Override
14163
public Object convert(final Object src, final Type dest) {
14264
// NB: Regardless of whether the destination type is an array or collection,
@@ -167,7 +89,6 @@ public Object convert(final Object src, final Type dest) {
16789

16890
@Override
16991
public <T> T convert(final Object src, final Class<T> dest) {
170-
// TODO: Would be better to split up this method into some helpers.
17192
if (dest == null) return null;
17293
if (src == null) return ConversionUtils.getNullValue(dest);
17394

@@ -360,4 +281,66 @@ private Collection<Object> createCollection(final Class<?> type) {
360281
return null;
361282
}
362283
}
284+
285+
// -- Deprecated API --
286+
287+
@Override
288+
@Deprecated
289+
public boolean canConvert(final Class<?> src, final Type dest) {
290+
291+
// Handle array types, including generic array types.
292+
if (isArray(dest)) return true;
293+
294+
// Handle parameterized collection types.
295+
if (dest instanceof ParameterizedType && isCollection(dest)) {
296+
return createCollection(GenericUtils.getClass(dest)) != null;
297+
}
298+
299+
return super.canConvert(src, dest);
300+
}
301+
302+
@Override
303+
@Deprecated
304+
public boolean canConvert(final Class<?> src, final Class<?> dest) {
305+
306+
if (src == null || dest == null) return true;
307+
308+
// ensure type is well-behaved, rather than a primitive type
309+
final Class<?> saneDest = ConversionUtils.getNonprimitiveType(dest);
310+
311+
// OK if the existing object can be casted
312+
if (ConversionUtils.canCast(src, saneDest)) return true;
313+
314+
// OK for numerical conversions
315+
if (ConversionUtils.canCast(ConversionUtils.getNonprimitiveType(src),
316+
Number.class) &&
317+
(ClassUtils.isByte(dest) || ClassUtils.isDouble(dest) ||
318+
ClassUtils.isFloat(dest) || ClassUtils.isInteger(dest) ||
319+
ClassUtils.isLong(dest) || ClassUtils.isShort(dest)))
320+
{
321+
return true;
322+
}
323+
324+
// OK if string
325+
if (saneDest == String.class) return true;
326+
327+
if (ConversionUtils.canCast(src, String.class)) {
328+
// OK if source type is string and destination type is character
329+
// (in this case, the first character of the string would be used)
330+
if (saneDest == Character.class) return true;
331+
332+
// OK if source type is string and destination type is an enum
333+
if (dest.isEnum()) return true;
334+
}
335+
336+
// OK if appropriate wrapper constructor exists
337+
try {
338+
return getConstructor(saneDest, src) != null;
339+
}
340+
catch (final Exception exc) {
341+
// TODO: Best not to catch blanket Exceptions here.
342+
// no known way to convert
343+
return false;
344+
}
345+
}
363346
}

0 commit comments

Comments
 (0)