Skip to content

Commit 6b594e6

Browse files
authored
Merge pull request #25 from twz123/consider-abstract-valuetransformers
Improve ValueTransformer type detection
2 parents e22ba07 + 7c05ec0 commit 6b594e6

File tree

8 files changed

+132
-96
lines changed

8 files changed

+132
-96
lines changed

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@
180180
<dependency>
181181
<groupId>com.google.guava</groupId>
182182
<artifactId>guava</artifactId>
183-
<version>14.0.1</version>
183+
<version>22.0</version>
184184
</dependency>
185185
<dependency>
186186
<groupId>javax.persistence</groupId>
@@ -195,7 +195,7 @@
195195
<dependency>
196196
<groupId>org.mockito</groupId>
197197
<artifactId>mockito-core</artifactId>
198-
<version>2.0.31-beta</version>
198+
<version>2.8.47</version>
199199
<scope>test</scope>
200200
</dependency>
201201
</dependencies>

src/main/java/de/zalando/sprocwrapper/globalvaluetransformer/GlobalValueTransformerLoader.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,20 @@ public boolean apply(final String input) {
6666
final Set<Class<?>> typesAnnotatedWith = reflections.getTypesAnnotatedWith(
6767
GlobalValueTransformer.class);
6868
for (final Class<?> foundGlobalValueTransformer : typesAnnotatedWith) {
69-
final Class<?> valueTransformerReturnType = ValueTransformerUtils.getUnmarshalFromDbClass(
70-
foundGlobalValueTransformer);
71-
if (valueTransformerReturnType != null) {
69+
final Class<?> valueTransformerReturnType;
70+
try {
71+
valueTransformerReturnType = ValueTransformerUtils.getUnmarshalFromDbClass(
72+
foundGlobalValueTransformer);
7273
GlobalValueTransformerRegistry.register(valueTransformerReturnType,
7374
(ValueTransformer<?, ?>) foundGlobalValueTransformer.newInstance());
74-
LOG.debug("Global Value Transformer [{}] for type [{}] registered. ",
75-
foundGlobalValueTransformer.getSimpleName(), valueTransformerReturnType.getSimpleName());
76-
} else {
77-
LOG.error(
78-
"Could add global transformer [{}] to global registry. Could not find method unmarshalFromDb.",
79-
foundGlobalValueTransformer);
75+
} catch (final RuntimeException e) {
76+
LOG.error("Failed to add global transformer [{}] to global registry.",
77+
foundGlobalValueTransformer, e);
78+
continue;
8079
}
80+
81+
LOG.debug("Global Value Transformer [{}] for type [{}] registered. ",
82+
foundGlobalValueTransformer.getSimpleName(), valueTransformerReturnType.getSimpleName());
8183
}
8284
}
8385

src/main/java/de/zalando/sprocwrapper/globalvaluetransformer/ReflectionUtils.java

Lines changed: 0 additions & 53 deletions
This file was deleted.
Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,43 @@
11
package de.zalando.sprocwrapper.globalvaluetransformer;
22

3+
import static com.google.common.base.Preconditions.checkArgument;
4+
35
import java.lang.reflect.Method;
6+
import java.lang.reflect.Type;
7+
8+
import com.google.common.reflect.TypeToken;
49

510
import de.zalando.typemapper.core.ValueTransformer;
611

712
public final class ValueTransformerUtils {
813
private ValueTransformerUtils() { }
914

10-
public static Class<?> getMarshalToDbClass(final Class<?> valueTransformer) {
11-
final Method method = ReflectionUtils.findMethod(valueTransformer, "marshalToDb");
12-
if (method != null) {
13-
return method.getReturnType();
14-
}
15+
public static Class<?> getMarshalToDbClass(final ValueTransformer<?, ?> valueTransformer) {
16+
return resolveReturnType(valueTransformer.getClass(), "marshalToDb", Object.class);
17+
}
1518

16-
return null;
19+
public static Class<?> getUnmarshalFromDbClass(final Class<?> clazz) {
20+
return resolveReturnType(checkValueTransformerClass(clazz), "unmarshalFromDb", String.class);
1721
}
1822

19-
public static Class<?> getUnmarshalFromDbClass(final Class<?> valueTransformerClass) {
20-
final Method method = ReflectionUtils.findMethod(valueTransformerClass, "unmarshalFromDb");
21-
if (method != null) {
22-
return method.getReturnType();
23-
}
23+
private static <T extends ValueTransformer<?, ?>> Class<?> resolveReturnType(final Class<T> actualClass,
24+
final String methodName, final Class<?>... methodParameterTypes) {
25+
final Method valueTransformerMethod = findValueTransformerMethod(methodName, methodParameterTypes);
26+
final Type genericReturnType = valueTransformerMethod.getGenericReturnType();
27+
return TypeToken.of(actualClass).resolveType(genericReturnType).getRawType();
28+
}
2429

25-
return null;
30+
private static Method findValueTransformerMethod(final String name, final Class<?>... parameterTypes) {
31+
try {
32+
return ValueTransformer.class.getMethod(name, parameterTypes);
33+
} catch (final NoSuchMethodException | SecurityException e) {
34+
throw new IllegalArgumentException("couldn't locate ValueTransformer method " + name, e);
35+
}
2636
}
2737

28-
public static Class<?> getMarshalToDbClass(final ValueTransformer<?, ?> valueTransformerForClass) {
29-
return valueTransformerForClass != null ? getMarshalToDbClass(valueTransformerForClass.getClass()) : null;
38+
@SuppressWarnings("unchecked")
39+
private static Class<? extends ValueTransformer<?, ?>> checkValueTransformerClass(final Class<?> clazz) {
40+
checkArgument(ValueTransformer.class.isAssignableFrom(clazz), "not a ValueTransformer: %s", clazz);
41+
return (Class<? extends ValueTransformer<?, ?>>) clazz;
3042
}
3143
}

src/main/java/de/zalando/sprocwrapper/proxy/GlobalValueTransformedParameter.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package de.zalando.sprocwrapper.proxy;
22

33
import java.lang.reflect.Method;
4-
import java.lang.reflect.Type;
54

65
import java.sql.Connection;
76

@@ -18,17 +17,15 @@
1817

1918
public class GlobalValueTransformedParameter extends StoredProcedureParameter {
2019

21-
private StoredProcedureParameter forwardingStoredProcedureParameter;
22-
@SuppressWarnings("rawtypes")
23-
private ValueTransformer valueTransformerForClass;
20+
private final StoredProcedureParameter forwardingStoredProcedureParameter;
2421

25-
@SuppressWarnings("rawtypes")
26-
private ObjectMapper globalObjectMapper;
22+
private final ValueTransformer<?, ?> valueTransformerForClass;
23+
24+
private final ObjectMapper<?> globalObjectMapper;
2725

2826
public GlobalValueTransformedParameter(final ValueTransformer<?, ?> valueTransformerForClass, final Class<?> clazz,
29-
final Type genericType, final Method m, final String typeName, final int sqlType, final int javaPosition,
30-
final boolean sensitive, final ObjectMapper<?> globalObjectMapper) throws InstantiationException,
31-
IllegalAccessException {
27+
final Method m, final String typeName, final int javaPosition, final boolean sensitive,
28+
final ObjectMapper<?> globalObjectMapper) throws InstantiationException, IllegalAccessException {
3229
super(getValueTransformedClazz(clazz, valueTransformerForClass), m, typeName, getValueTransformedTypeId(clazz),
3330
javaPosition, sensitive);
3431

@@ -64,11 +61,12 @@ public Object mapParam(final Object value, final Connection connection) {
6461
}
6562
}
6663

64+
@SuppressWarnings("unchecked")
6765
private Object getMarshaledObject(final Object o) {
6866
if (globalObjectMapper != null) {
69-
return globalObjectMapper.marshalToDb(o);
67+
return ((ObjectMapper<Object>) globalObjectMapper).marshalToDb(o);
7068
} else {
71-
return valueTransformerForClass.marshalToDb(o);
69+
return ((ValueTransformer<?, Object>) valueTransformerForClass).marshalToDb(o);
7270
}
7371
}
7472

src/main/java/de/zalando/sprocwrapper/proxy/SProcProxy.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import org.slf4j.Logger;
88
import org.slf4j.LoggerFactory;
99

10-
import com.google.common.base.Objects;
10+
import com.google.common.base.MoreObjects;
1111
import com.google.common.reflect.AbstractInvocationHandler;
1212

1313
import de.zalando.sprocwrapper.dsprovider.DataSourceProvider;
@@ -56,9 +56,9 @@ protected Object handleInvocation(final Object proxy, final Method method, final
5656
@Override
5757
public String toString() {
5858
return
59-
Objects.toStringHelper(this) //
60-
.addValue(description) //
61-
.add("dataSourceProvider", dataSourceProvider) //
62-
.toString();
59+
MoreObjects.toStringHelper(this) //
60+
.addValue(description) //
61+
.add("dataSourceProvider", dataSourceProvider) //
62+
.toString();
6363
}
6464
}

src/main/java/de/zalando/sprocwrapper/proxy/StoredProcedureParameter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ public static StoredProcedureParameter createParameter(final Class<?> clazz, fin
6767
if (valueTransformerForClass != null) {
6868

6969
// inject the additional logic to transform types and values
70-
return new GlobalValueTransformedParameter(valueTransformerForClass, clazz, genericType, m, typeName,
71-
sqlType, javaPosition, sensitive, globalObjectMapper);
70+
return new GlobalValueTransformedParameter(valueTransformerForClass, clazz, m, typeName, javaPosition,
71+
sensitive, globalObjectMapper);
7272
} else {
7373
Integer typeId = sqlType;
7474
if (typeId == null || typeId == -1) {
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package de.zalando.sprocwrapper.globalvaluetransformer;
2+
3+
import static org.hamcrest.CoreMatchers.is;
4+
import static org.hamcrest.CoreMatchers.sameInstance;
5+
6+
import static org.hamcrest.MatcherAssert.assertThat;
7+
8+
import org.junit.Test;
9+
10+
import de.zalando.typemapper.core.ValueTransformer;
11+
12+
public class ValueTransformerUtilsTest {
13+
14+
/**
15+
* A custom value that shall be transformed using a {@link ValueTransformer}.
16+
*/
17+
public static class CustomValue {
18+
// just a dummy type
19+
}
20+
21+
/**
22+
* A custom bound that shall be transformed using a {@link ValueTransformer}.
23+
*/
24+
public static class CustomBound {
25+
// just a dummy type
26+
}
27+
28+
/**
29+
* An example for an abstract parameterized transformer that does &quot;something&quot; and then delegates to a
30+
* subclass's method.
31+
*/
32+
public abstract static class AbstractParameterizedTransformer<Value, Bound> extends ValueTransformer<Value, Bound> {
33+
34+
@Override
35+
public Bound unmarshalFromDb(final String value) {
36+
return delegatedUnmarshalling(value);
37+
}
38+
39+
@Override
40+
public Value marshalToDb(final Bound bound) {
41+
return delegatedMarshalling(bound);
42+
}
43+
44+
// actual unmarshalling performed by subclasses that operate on a preprocessed value
45+
protected abstract Bound delegatedUnmarshalling(String preprocessed);
46+
47+
// actual marshalling performed by subclasses that operate on a preprocessed value
48+
protected abstract Value delegatedMarshalling(Bound preprocessed);
49+
}
50+
51+
/**
52+
* An example for a concrete transformer that uses an abstract parameterized transformer as a superclass.
53+
*/
54+
public static class ConcreteTransformer extends AbstractParameterizedTransformer<CustomValue, CustomBound> {
55+
@Override
56+
protected CustomBound delegatedUnmarshalling(final String preprocessed) {
57+
return null; // doesn't do anything meaningful, just an example
58+
}
59+
60+
@Override
61+
protected CustomValue delegatedMarshalling(final CustomBound preprocessed) {
62+
return null; // doesn't do anything meaningful, just an example
63+
}
64+
}
65+
66+
@Test
67+
public void resolvesParamterizedUnmarshalReturnType() {
68+
assertThat(ValueTransformerUtils.getUnmarshalFromDbClass(ConcreteTransformer.class),
69+
is(sameInstance((Object) CustomBound.class)));
70+
}
71+
72+
@Test
73+
public void resolvesParamterizedMarshalReturnType() {
74+
assertThat(ValueTransformerUtils.getMarshalToDbClass(new ConcreteTransformer()),
75+
is(sameInstance((Object) CustomValue.class)));
76+
}
77+
}

0 commit comments

Comments
 (0)