diff --git a/src/main/java/org/springframework/data/projection/ProxyProjectionFactory.java b/src/main/java/org/springframework/data/projection/ProxyProjectionFactory.java index 1691df5d3..649ad688e 100644 --- a/src/main/java/org/springframework/data/projection/ProxyProjectionFactory.java +++ b/src/main/java/org/springframework/data/projection/ProxyProjectionFactory.java @@ -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 { 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 { 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 { 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(); diff --git a/src/main/java/org/springframework/data/projection/TargetAware.java b/src/main/java/org/springframework/data/projection/TargetAware.java new file mode 100644 index 000000000..217ab1d4e --- /dev/null +++ b/src/main/java/org/springframework/data/projection/TargetAware.java @@ -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(); +} diff --git a/src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java b/src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java index 07831f63f..52b9f41a1 100644 --- a/src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java +++ b/src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java @@ -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;