Skip to content

Commit 7f7d216

Browse files
committed
DATACMNS-782 - ProxyProjectionFactory now converts primitive attribute values.
The ProjectingMethodInterceptor now uses a default ConversionService instance to try to convert a potentially not matching result of the target invocation into the type the projection requires before the attempt to create nested projection.
1 parent c81b37c commit 7f7d216

File tree

2 files changed

+44
-3
lines changed

2 files changed

+44
-3
lines changed

src/main/java/org/springframework/data/projection/ProjectingMethodInterceptor.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import org.aopalliance.intercept.MethodInterceptor;
2727
import org.aopalliance.intercept.MethodInvocation;
2828
import org.springframework.core.CollectionFactory;
29+
import org.springframework.core.convert.ConversionService;
30+
import org.springframework.core.convert.support.DefaultConversionService;
2931
import org.springframework.data.util.ClassTypeInformation;
3032
import org.springframework.data.util.TypeInformation;
3133
import org.springframework.util.Assert;
@@ -43,6 +45,7 @@ class ProjectingMethodInterceptor implements MethodInterceptor {
4345

4446
private final ProjectionFactory factory;
4547
private final MethodInterceptor delegate;
48+
private final ConversionService conversionService;
4649

4750
/**
4851
* Creates a new {@link ProjectingMethodInterceptor} using the given {@link ProjectionFactory} and delegate
@@ -59,6 +62,7 @@ public ProjectingMethodInterceptor(ProjectionFactory factory, MethodInterceptor
5962

6063
this.factory = factory;
6164
this.delegate = delegate;
65+
this.conversionService = new DefaultConversionService();
6266
}
6367

6468
/*
@@ -75,13 +79,16 @@ public Object invoke(MethodInvocation invocation) throws Throwable {
7579
}
7680

7781
TypeInformation<?> type = ClassTypeInformation.fromReturnTypeOf(invocation.getMethod());
82+
Class<?> rawType = type.getType();
7883

79-
if (type.isCollectionLike() && !ClassUtils.isPrimitiveArray(type.getType())) {
84+
if (type.isCollectionLike() && !ClassUtils.isPrimitiveArray(rawType)) {
8085
return projectCollectionElements(asCollection(result), type);
8186
} else if (type.isMap()) {
8287
return projectMapValues((Map<?, ?>) result, type);
88+
} else if (conversionRequiredAndPossible(result, rawType)) {
89+
return conversionService.convert(result, rawType);
8390
} else {
84-
return getProjection(result, type.getType());
91+
return getProjection(result, rawType);
8592
}
8693
}
8794

@@ -134,6 +141,23 @@ private Object getProjection(Object result, Class<?> returnType) {
134141
: factory.createProjection(returnType, result);
135142
}
136143

144+
/**
145+
* Returns whether the source object needs to be converted to the given target type and whether we can convert it at
146+
* all.
147+
*
148+
* @param source can be {@literal null}.
149+
* @param targetType must not be {@literal null}.
150+
* @return
151+
*/
152+
private boolean conversionRequiredAndPossible(Object source, Class<?> targetType) {
153+
154+
if (source == null || targetType.isInstance(source)) {
155+
return false;
156+
}
157+
158+
return conversionService.canConvert(source.getClass(), targetType);
159+
}
160+
137161
/**
138162
* Turns the given value into a {@link Collection}. Will turn an array into a collection an wrap all other values into
139163
* a single-element collection.

src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public void returnsAllPropertiesAsInputProperties() {
157157

158158
List<String> result = factory.getInputProperties(CustomerExcerpt.class);
159159

160-
assertThat(result, hasSize(4));
160+
assertThat(result, hasSize(5));
161161
assertThat(result, hasItems("firstname", "address", "shippingAddresses", "picture"));
162162
}
163163

@@ -220,8 +220,23 @@ public void projectsNonPrimitiveArray() {
220220
assertThat(excerpt.getShippingAddresses(), is(arrayWithSize(1)));
221221
}
222222

223+
/**
224+
* @see DATACMNS-782
225+
*/
226+
@Test
227+
public void convertsPrimitiveValues() {
228+
229+
Customer customer = new Customer();
230+
customer.id = 1L;
231+
232+
CustomerExcerpt excerpt = factory.createProjection(CustomerExcerpt.class, customer);
233+
234+
assertThat(excerpt.getId(), is(customer.id.toString()));
235+
}
236+
223237
static class Customer {
224238

239+
public Long id;
225240
public String firstname, lastname;
226241
public Address address;
227242
public byte[] picture;
@@ -235,6 +250,8 @@ static class Address {
235250

236251
interface CustomerExcerpt {
237252

253+
String getId();
254+
238255
String getFirstname();
239256

240257
AddressExcerpt getAddress();

0 commit comments

Comments
 (0)