Skip to content

Commit 4e13436

Browse files
committed
Create ConversionService
Adds a new HandlerService: ConversionService, operating on ConversionHandler plugins. The purpose of these handlers is to process a new class, "ConversionRequest", which signifies the desire to cast or convert an object of one type to another. This will take the place of ConversionUtils, as it is an extensible framework. ConversionHandler plugins can decide what types of conversion they support and thus override the default behavior (the default plugin supports primitive : object conversions and cases where the destination object has a constructor that will accept the source, for example). Closes #95
1 parent f76c9e3 commit 4e13436

File tree

8 files changed

+950
-0
lines changed

8 files changed

+950
-0
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2014 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava.util.conversion;
33+
34+
import org.scijava.plugin.AbstractHandlerPlugin;
35+
36+
/**
37+
* Abstract superclass for {@link ConversionHandler} plugins. Performs
38+
* appropriate dispatching of {@link #canConvert(ConversionRequest)} and
39+
* {@link #convert(ConversionRequest)} calls based on the actual state of the
40+
* given {@link ConversionRequest}.
41+
* <p>
42+
* Note that the {@link #supports(ConversionRequest)} method is overridden as
43+
* well, to delegate to the appropriate {@link #canConvert}.
44+
* </p>
45+
*
46+
* @author Mark Hiner
47+
*/
48+
public abstract class AbstractConversionHandler extends
49+
AbstractHandlerPlugin<ConversionRequest> implements ConversionHandler
50+
{
51+
52+
// -- ConversionHandler methods --
53+
54+
@Override
55+
public boolean canConvert(final ConversionRequest request) {
56+
final Class<?> src = request.sourceClass();
57+
if (src == null) return true;
58+
59+
if (request.destClass() != null) return canConvert(src, request.destClass());
60+
if (request.destType() != null) return canConvert(src, request.destType());
61+
62+
return false;
63+
}
64+
65+
@Override
66+
public Object convert(final ConversionRequest request) {
67+
if (request.sourceObject() != null) {
68+
if (request.destClass() != null) return convert(request.sourceObject(),
69+
request.destClass());
70+
71+
if (request.destType() != null) return convert(request.sourceObject(),
72+
request.destType());
73+
}
74+
return null;
75+
}
76+
77+
// -- Typed methods --
78+
79+
@Override
80+
public boolean supports(final ConversionRequest request) {
81+
return canConvert(request);
82+
}
83+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2014 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava.util.conversion;
33+
34+
import org.scijava.plugin.AbstractHandlerService;
35+
36+
/**
37+
* Abstract superclass for {@link ConversionService} implementations
38+
* @author Mark Hiner
39+
*/
40+
public abstract class AbstractConversionService extends
41+
AbstractHandlerService<ConversionRequest, ConversionHandler> implements
42+
ConversionService
43+
{
44+
// NB empty implementation
45+
}
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2014 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava.util.conversion;
33+
34+
import java.lang.reflect.Type;
35+
import java.util.Collection;
36+
import java.util.List;
37+
import java.util.Set;
38+
39+
import org.scijava.plugin.HandlerPlugin;
40+
import org.scijava.plugin.Plugin;
41+
42+
/**
43+
* Extensible conversion {@link Plugin} for converting between classes and
44+
* types.
45+
*
46+
* @see ConversionRequest
47+
* @author Mark Hiner
48+
*/
49+
public interface ConversionHandler extends HandlerPlugin<ConversionRequest> {
50+
51+
/**
52+
* Checks whether a given {@ConversionRequest} can be
53+
* processed, by converting the desired
54+
* {@link ConversionRequest#sourceClass()} to its
55+
* {@link ConversionRequest#destClass()} or
56+
* {@link ConversionRequest#destType()}.
57+
*
58+
* @see #convert(ConversionRequest)
59+
*/
60+
boolean canConvert(ConversionRequest request);
61+
62+
/**
63+
* Checks whether objects of the given class can be converted to the specified
64+
* type.
65+
*
66+
* @see #convert(Object, Type)
67+
*/
68+
boolean canConvert(Class<?> src, Type dest);
69+
70+
/**
71+
* Checks whether objects of the given class can be converted to the specified
72+
* type.
73+
*
74+
* @see #convert(Object, Class)
75+
*/
76+
boolean canConvert(Class<?> src, Class<?> dest);
77+
78+
/**
79+
* Checks whether the given object's type can be converted to the specified
80+
* type.
81+
* <p>
82+
* Note that this does <em>not</em> necessarily entail that
83+
* {@link #convert(Object, Type)} on that specific object will succeed. For
84+
* example: {@code canConvert("5.1", int.class)} will return {@code true}
85+
* because a {@link String} can in general be converted to an {@code int}, but
86+
* calling {@code convert("5.1", int.class)} will throw a
87+
* {@link NumberFormatException} when the conversion is actually attempted via
88+
* the {@link Integer#Integer(String)} constructor.
89+
* </p>
90+
*
91+
* @see #convert(Object, Type)
92+
*/
93+
boolean canConvert(Object src, Type dest);
94+
95+
/**
96+
* Checks whether the given object's type can be converted to the specified
97+
* type.
98+
* <p>
99+
* Note that this does <em>not</em> necessarily entail that
100+
* {@link #convert(Object, Class)} on that specific object will succeed. For
101+
* example: {@code canConvert("5.1", int.class)} will return {@code true}
102+
* because a {@link String} can in general be converted to an {@code int}, but
103+
* calling {@code convert("5.1", int.class)} will throw a
104+
* {@link NumberFormatException} when the conversion is actually attempted via
105+
* the {@link Integer#Integer(String)} constructor.
106+
* </p>
107+
*
108+
* @see #convert(Object, Class)
109+
*/
110+
boolean canConvert(Object src, Class<?> dest);
111+
112+
/**
113+
* As {@link #convert(Object, Class)} but capable of creating and populating
114+
* multi-element objects ({@link Collection}s and array types). If a single
115+
* element type is provided, it will be converted the same as
116+
* {@link #convert(Object, Class)}. If a multi-element type is detected, then
117+
* the value parameter will be interpreted as potential collection of values.
118+
* An appropriate container will be created, and the full set of values will
119+
* be type converted and added.
120+
* <p>
121+
* NB: This method should be capable of creating any array type, but if a
122+
* {@link Collection} interface or abstract class is provided we can only make
123+
* a best guess as to what container type to instantiate. Defaults are
124+
* provided for {@link Set} and {@link List} subclasses.
125+
* </p>
126+
*
127+
* @param src The object to convert.
128+
* @param dest Type to which the object should be converted.
129+
*/
130+
Object convert(Object src, Type dest);
131+
132+
/**
133+
* Converts the given object to an object of the specified type. The object is
134+
* casted directly if possible, or else a new object is created using the
135+
* destination type's public constructor that takes the original object as
136+
* input (except when converting to {@link String}, which uses the
137+
* {@link Object#toString()} method instead). In the case of primitive types,
138+
* returns an object of the corresponding wrapped type. If the destination
139+
* type does not have an appropriate constructor, returns null.
140+
*
141+
* @param <T> Type to which the object should be converted.
142+
* @param src The object to convert.
143+
* @param dest Type to which the object should be converted.
144+
*/
145+
<T> T convert(Object src, Class<T> dest);
146+
147+
/**
148+
* Converts the given {@link ConversionRequest#sourceObject()} to the
149+
* specified {@link ConversionRequest#destClass()} or
150+
* {@link ConversionRequest#destType()}.
151+
*
152+
* @see #convert(Object, Class)
153+
* @see #convert(Object, Type)
154+
* @param request {@link ConversionRequest} to process.
155+
* @return The conversion output
156+
*/
157+
Object convert(ConversionRequest request);
158+
}

0 commit comments

Comments
 (0)