Browse Source

DATAREST-684 - ProxyProjectionFactory now exposes target instance on proxy.

Changed TargetClassAware to TargetAware and expose the actual proxy target for framework purposes.
pull/120/merge
Oliver Gierke 11 years ago
parent
commit
cb78260322
  1. 40
      src/main/java/org/springframework/data/projection/ProxyProjectionFactory.java
  2. 44
      src/main/java/org/springframework/data/projection/TargetAware.java
  3. 12
      src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java

40
src/main/java/org/springframework/data/projection/ProxyProjectionFactory.java

@ -29,8 +29,6 @@ import org.springframework.aop.framework.ProxyFactory; @@ -29,8 +29,6 @@ import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.util.Assert;
import com.fasterxml.jackson.annotation.JsonIgnore;
/**
* A {@link ProjectionFactory} to create JDK proxies to back interfaces and handle method invocations on them. By
* default accessor methods are supported. In case the delegating lookups result in an object of different type that the
@ -64,13 +62,13 @@ class ProxyProjectionFactory implements ProjectionFactory { @@ -64,13 +62,13 @@ class ProxyProjectionFactory implements ProjectionFactory {
ProxyFactory factory = new ProxyFactory();
factory.setTarget(source);
factory.setOpaque(true);
factory.setInterfaces(projectionType, TargetClassAware.class);
factory.setInterfaces(projectionType, TargetAware.class);
if (IS_JAVA_8) {
factory.addAdvice(new DefaultMethodInvokingMethodInterceptor());
}
factory.addAdvice(new TargetClassAwareMethodInterceptor(source.getClass()));
factory.addAdvice(new TargetAwareMethodInterceptor(source.getClass()));
factory.addAdvice(getMethodInterceptor(source, projectionType));
return (T) factory.getProxy(getClass().getClassLoader());
@ -152,45 +150,37 @@ class ProxyProjectionFactory implements ProjectionFactory { @@ -152,45 +150,37 @@ class ProxyProjectionFactory implements ProjectionFactory {
return true;
}
/**
* Extension of {@link org.springframework.aop.TargetClassAware} to be able to ignore the getter on JSON rendering.
*
* @author Oliver Gierke
*/
public static interface TargetClassAware extends org.springframework.aop.TargetClassAware {
@JsonIgnore
Class<?> getTargetClass();
}
/**
* Custom {@link MethodInterceptor} to expose the proxy target class even if we set
* {@link ProxyFactory#setOpaque(boolean)} to true to prevent properties on {@link Advised} to be rendered.
*
* @author Oliver Gierke
*/
private static class TargetClassAwareMethodInterceptor implements MethodInterceptor {
private static class TargetAwareMethodInterceptor implements MethodInterceptor {
private static final Method GET_TARGET_CLASS_METHOD;
private final Class<?> targetClass;
private static final Method GET_TARGET_METHOD;
private final Class<?> targetType;
static {
try {
GET_TARGET_CLASS_METHOD = TargetClassAware.class.getMethod("getTargetClass");
GET_TARGET_CLASS_METHOD = TargetAware.class.getMethod("getTargetClass");
GET_TARGET_METHOD = TargetAware.class.getMethod("getTarget");
} catch (NoSuchMethodException e) {
throw new IllegalStateException(e);
}
}
/**
* Creates a new {@link TargetClassAwareMethodInterceptor} with the given target class.
* Creates a new {@link TargetAwareMethodInterceptor} with the given target class.
*
* @param targetClass must not be {@literal null}.
* @param targetType must not be {@literal null}.
*/
public TargetClassAwareMethodInterceptor(Class<?> targetClass) {
public TargetAwareMethodInterceptor(Class<?> targetType) {
Assert.notNull(targetClass, "Target class must not be null!");
this.targetClass = targetClass;
Assert.notNull(targetType, "Target type must not be null!");
this.targetType = targetType;
}
/*
@ -201,7 +191,9 @@ class ProxyProjectionFactory implements ProjectionFactory { @@ -201,7 +191,9 @@ class ProxyProjectionFactory implements ProjectionFactory {
public Object invoke(MethodInvocation invocation) throws Throwable {
if (invocation.getMethod().equals(GET_TARGET_CLASS_METHOD)) {
return targetClass;
return targetType;
} else if (invocation.getMethod().equals(GET_TARGET_METHOD)) {
return invocation.getThis();
}
return invocation.proceed();

44
src/main/java/org/springframework/data/projection/TargetAware.java

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
/*
* Copyright 2015 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.projection;
import org.springframework.aop.RawTargetAccess;
import com.fasterxml.jackson.annotation.JsonIgnore;
/**
* Extension of {@link org.springframework.aop.TargetClassAware} to be able to ignore the getter on JSON rendering.
*
* @author Oliver Gierke
*/
public interface TargetAware extends org.springframework.aop.TargetClassAware, RawTargetAccess {
/**
* Returns the type of the proxy target.
*
* @return will never be {@literal null}.
*/
@JsonIgnore
Class<?> getTargetClass();
/**
* Returns the proxy target.
*
* @return will never be {@literal null}.
*/
@JsonIgnore
Object getTarget();
}

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

@ -176,6 +176,18 @@ public class ProxyProjectionFactoryUnitTests { @@ -176,6 +176,18 @@ public class ProxyProjectionFactoryUnitTests {
assertThat(advisors[0].getAdvice(), is(instanceOf(DefaultMethodInvokingMethodInterceptor.class)));
}
/**
* @see DATACMNS-648
*/
@Test
public void exposesProxyTarget() {
CustomerExcerpt excerpt = factory.createProjection(CustomerExcerpt.class);
assertThat(excerpt, is(instanceOf(TargetAware.class)));
assertThat(((TargetAware) excerpt).getTarget(), is(instanceOf(Map.class)));
}
static class Customer {
public String firstname, lastname;

Loading…
Cancel
Save