Browse Source

DATACMNS-820 - Allow setter invocations in projections backed by beans.

Invocations to setter methods are now passed to the backing bean.

Original pull request: #155.
pull/156/head
Mark Paluch 10 years ago committed by Oliver Gierke
parent
commit
e868577def
  1. 17
      src/main/java/org/springframework/data/projection/PropertyAccessingMethodInterceptor.java
  2. 49
      src/test/java/org/springframework/data/projection/PropertyAccessingMethodInterceptorUnitTests.java
  3. 47
      src/test/java/org/springframework/data/projection/SpelAwareProxyProjectionFactoryUnitTests.java

17
src/main/java/org/springframework/data/projection/PropertyAccessingMethodInterceptor.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2014-2015 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -30,6 +30,7 @@ import org.springframework.util.ReflectionUtils; @@ -30,6 +30,7 @@ import org.springframework.util.ReflectionUtils;
* Method interceptor to forward a delegation to bean property accessor methods to the property of a given target.
*
* @author Oliver Gierke
* @author Mark Paluch
* @since 1.10
*/
class PropertyAccessingMethodInterceptor implements MethodInterceptor {
@ -66,6 +67,20 @@ class PropertyAccessingMethodInterceptor implements MethodInterceptor { @@ -66,6 +67,20 @@ class PropertyAccessingMethodInterceptor implements MethodInterceptor {
throw new IllegalStateException("Invoked method is not a property accessor!");
}
if (isSetterMethod(method, descriptor)) {
if (invocation.getArguments().length != 1) {
throw new IllegalStateException("Invoked setter method requires exactly one argument!");
}
target.setPropertyValue(descriptor.getName(), invocation.getArguments()[0]);
return null;
}
return target.getPropertyValue(descriptor.getName());
}
private boolean isSetterMethod(Method method, PropertyDescriptor descriptor) {
return method.equals(descriptor.getWriteMethod());
}
}

49
src/test/java/org/springframework/data/projection/PropertyAccessingMethodInterceptorUnitTests.java

@ -26,6 +26,7 @@ import org.junit.runner.RunWith; @@ -26,6 +26,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.beans.NotReadablePropertyException;
import org.springframework.beans.NotWritablePropertyException;
/**
* Unit tests for {@link PropertyAccessingMethodInterceptor}.
@ -62,6 +63,50 @@ public class PropertyAccessingMethodInterceptorUnitTests { @@ -62,6 +63,50 @@ public class PropertyAccessingMethodInterceptorUnitTests {
new PropertyAccessingMethodInterceptor(new Source()).invoke(invocation);
}
/**
* @see DATACMNS-820
*/
@Test
public void triggersWritePropertyAccessOnTarget() throws Throwable {
Source source = new Source();
source.firstname = "Dave";
when(invocation.getMethod()).thenReturn(Projection.class.getMethod("setFirstname", String.class));
when(invocation.getArguments()).thenReturn(new Object[] { "Carl" });
MethodInterceptor interceptor = new PropertyAccessingMethodInterceptor(source);
interceptor.invoke(invocation);
assertThat(source.firstname, is((Object) "Carl"));
}
/**
* @see DATACMNS-820
*/
@Test(expected = IllegalStateException.class)
public void throwsAppropriateExceptionIfTheInvocationHasNoArguments() throws Throwable {
Source source = new Source();
when(invocation.getMethod()).thenReturn(Projection.class.getMethod("setFirstname", String.class));
when(invocation.getArguments()).thenReturn(new Object[0]);
MethodInterceptor interceptor = new PropertyAccessingMethodInterceptor(source);
interceptor.invoke(invocation);
}
/**
* @see DATACMNS-820
*/
@Test(expected = NotWritablePropertyException.class)
public void throwsAppropriateExceptionIfThePropertyCannotWritten() throws Throwable {
when(invocation.getMethod()).thenReturn(Projection.class.getMethod("setGarbage", String.class));
when(invocation.getArguments()).thenReturn(new Object[] { "Carl" });
new PropertyAccessingMethodInterceptor(new Source()).invoke(invocation);
}
/**
* @see DATAREST-221
*/
@ -91,6 +136,10 @@ public class PropertyAccessingMethodInterceptorUnitTests { @@ -91,6 +136,10 @@ public class PropertyAccessingMethodInterceptorUnitTests {
String getFirstname();
void setFirstname(String firstname);
void setGarbage(String garbage);
String getLastname();
String someGarbage();

47
src/test/java/org/springframework/data/projection/SpelAwareProxyProjectionFactoryUnitTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -22,6 +22,7 @@ import java.util.List; @@ -22,6 +22,7 @@ import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.NotWritablePropertyException;
import org.springframework.beans.factory.annotation.Value;
/**
@ -29,6 +30,7 @@ import org.springframework.beans.factory.annotation.Value; @@ -29,6 +30,7 @@ import org.springframework.beans.factory.annotation.Value;
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
*/
public class SpelAwareProxyProjectionFactoryUnitTests {
@ -53,6 +55,42 @@ public class SpelAwareProxyProjectionFactoryUnitTests { @@ -53,6 +55,42 @@ public class SpelAwareProxyProjectionFactoryUnitTests {
assertThat(excerpt.getFullName(), is("Dave Matthews"));
}
/**
* @see DATACMNS-820
*/
@Test
public void setsValueUsingProjection() {
Customer customer = new Customer();
customer.firstname = "Dave";
CustomerExcerpt excerpt = factory.createProjection(CustomerExcerpt.class, customer);
excerpt.setFirstname("Carl");
assertThat(customer.firstname, is("Carl"));
}
/**
* @see DATACMNS-820
*/
@Test
public void settingNotWriteablePropertyFails() {
Customer customer = new Customer();
customer.firstname = "Dave";
ProjectionWithNotWriteableProperty projection = factory.createProjection(ProjectionWithNotWriteableProperty.class,
customer);
try {
projection.setFirstName("Carl");
fail("Missing NotWritablePropertyException");
} catch (NotWritablePropertyException e) {
assertThat(e, instanceOf(NotWritablePropertyException.class));
}
}
/**
* @see DATACMNS-630
*/
@ -87,5 +125,12 @@ public class SpelAwareProxyProjectionFactoryUnitTests { @@ -87,5 +125,12 @@ public class SpelAwareProxyProjectionFactoryUnitTests {
String getFullName();
String getFirstname();
void setFirstname(String firstname);
}
interface ProjectionWithNotWriteableProperty {
void setFirstName(String firstname);
}
}

Loading…
Cancel
Save