diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/persistence/AbstractConstructorEntityInstantiator.java b/spring-data-commons-core/src/main/java/org/springframework/data/persistence/AbstractConstructorEntityInstantiator.java index 6f1fdab81..146a70c11 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/persistence/AbstractConstructorEntityInstantiator.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/persistence/AbstractConstructorEntityInstantiator.java @@ -3,6 +3,7 @@ package org.springframework.data.persistence; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.ClassUtils; +import sun.reflect.ReflectionFactory; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -20,7 +21,7 @@ public abstract class AbstractConstructorEntityInstantiator,StateBackedCreator> cache = new HashMap,StateBackedCreator>(); - final public T createEntityFromState(STATE n, Class c) { + public T createEntityFromState(STATE n, Class c) { try { StateBackedCreator creator = (StateBackedCreator) cache.get(c); if (creator !=null) return creator.create(n,c); @@ -47,34 +48,34 @@ public abstract class AbstractConstructorEntityInstantiator StateBackedCreator createInstantiator(Class type, final Class stateType) { - StateBackedCreator creator =stateTakingConstructorInstantiator(type,stateType); + StateBackedCreator creator = stateTakingConstructorInstantiator(type,stateType); if (creator !=null) return creator; creator = emptyConstructorStateSettingInstantiator(type,stateType); if (creator !=null) return creator; return createFailingInstantiator(stateType); } - private StateBackedCreator createFailingInstantiator(final Class stateType) { + protected StateBackedCreator createFailingInstantiator(final Class stateType) { return new StateBackedCreator() { - public T create(STATE n, Class c) throws Exception { + public T create(STATE state, Class c) throws Exception { throw new IllegalArgumentException(getClass().getSimpleName() + ": entity " + c + " must have either a constructor taking [" + stateType + "] or a no-arg constructor and state set method"); } }; } - private StateBackedCreator emptyConstructorStateSettingInstantiator(Class type, Class stateType) { + protected StateBackedCreator emptyConstructorStateSettingInstantiator(Class type, Class stateType) { final Constructor constructor = getNoArgConstructor(type); if (constructor == null) return null; log.info("Using " + type + " no-arg constructor"); return new StateBackedCreator() { - public T create(STATE n, Class c) throws Exception { + public T create(STATE state, Class c) throws Exception { try { - StateProvider.setUnderlyingState(n); + StateProvider.setUnderlyingState(state); T newInstance = constructor.newInstance(); - setState(newInstance, n); + setState(newInstance, state); return newInstance; } finally { StateProvider.retrieveState(); @@ -83,13 +84,28 @@ public abstract class AbstractConstructorEntityInstantiator Constructor getNoArgConstructor(Class type) { + @SuppressWarnings("unchecked") + protected StateBackedCreator createWithoutConstructorInvocation(final Class type, Class stateType) { + ReflectionFactory rf = ReflectionFactory.getReflectionFactory(); + Constructor objectConstructor = getDeclaredConstructor(Object.class); + final Constructor serializationConstructor = rf.newConstructorForSerialization(type, objectConstructor); + return new StateBackedCreator() { + public T create(STATE state, Class c) throws Exception { + final T result = type.cast(serializationConstructor.newInstance()); + setState(result,state); + return result; + } + }; + } + + + protected Constructor getNoArgConstructor(Class type) { Constructor constructor = ClassUtils.getConstructorIfAvailable(type); if (constructor != null) return constructor; return getDeclaredConstructor(type); } - private StateBackedCreator stateTakingConstructorInstantiator(Class type, Class stateType) { + protected StateBackedCreator stateTakingConstructorInstantiator(Class type, Class stateType) { Class stateInterface = (Class) stateType.getInterfaces()[0]; final Constructor constructor = ClassUtils.getConstructorIfAvailable(type, stateInterface); if (constructor == null) return null; @@ -102,7 +118,7 @@ public abstract class AbstractConstructorEntityInstantiator Constructor getDeclaredConstructor(Class c) { + protected Constructor getDeclaredConstructor(Class c) { try { final Constructor declaredConstructor = c.getDeclaredConstructor(); declaredConstructor.setAccessible(true);