DATACMNS-867 - First draft.
This commit is contained in:
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* 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.convert;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.model.ParameterValueProvider;
|
||||
|
||||
/**
|
||||
* An {@link EntityInstantiator} that can generate byte code to speed-up dynamic object instantiation. Uses the
|
||||
* {@link PersistentEntity}'s {@link PreferredConstructor} to instantiate an instance of the entity by dynamically
|
||||
* generating factory methods with appropriate constructor invocations via ASM. If we cannot generate byte code for a
|
||||
* type, we gracefully fall-back to the {@link ReflectionEntityInstantiator}.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @since 1.10
|
||||
* @deprecated since 1.11 in favor of {@link ClassGeneratingEntityInstantiator}.
|
||||
*/
|
||||
@Deprecated
|
||||
public enum BytecodeGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
private final ClassGeneratingEntityInstantiator delegate = new ClassGeneratingEntityInstantiator();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.EntityInstantiator#createInstance(org.springframework.data.mapping.PersistentEntity, org.springframework.data.mapping.model.ParameterValueProvider)
|
||||
*/
|
||||
@Override
|
||||
public <T, E extends PersistentEntity<? extends T, P>, P extends PersistentProperty<P>> T createInstance(E entity,
|
||||
ParameterValueProvider<P> provider) {
|
||||
|
||||
return this.delegate.createInstance(entity, provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Thomas Darimont
|
||||
* @deprecated
|
||||
*/
|
||||
public interface ObjectInstantiator {
|
||||
|
||||
Object newInstance(Object... args);
|
||||
}
|
||||
}
|
||||
@@ -21,11 +21,10 @@ import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.asm.ClassWriter;
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
@@ -34,7 +33,6 @@ import org.springframework.asm.Type;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.data.mapping.model.MappingInstantiationException;
|
||||
import org.springframework.data.mapping.model.ParameterValueProvider;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
@@ -140,12 +138,10 @@ public class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
return true;
|
||||
}
|
||||
|
||||
PreferredConstructor<?, ?> persistenceConstructor = entity.getPersistenceConstructor();
|
||||
if (persistenceConstructor == null || !Modifier.isPublic(persistenceConstructor.getConstructor().getModifiers())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return entity.getPersistenceConstructor()//
|
||||
.map(PreferredConstructor::getConstructor)//
|
||||
.map(Constructor::getModifiers)//
|
||||
.map(modifier -> !Modifier.isPublic(modifier)).orElse(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,7 +196,7 @@ public class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
try {
|
||||
return (T) instantiator.newInstance(params);
|
||||
} catch (Exception e) {
|
||||
throw new MappingInstantiationException(entity, Arrays.asList(params), e);
|
||||
throw new MappingInstantiationException(Optional.of(entity), Arrays.asList(params), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,19 +208,19 @@ public class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
* @return
|
||||
*/
|
||||
private <P extends PersistentProperty<P>, T> Object[] extractInvocationArguments(
|
||||
PreferredConstructor<? extends T, P> constructor, ParameterValueProvider<P> provider) {
|
||||
Optional<? extends PreferredConstructor<? extends T, P>> constructor, ParameterValueProvider<P> provider) {
|
||||
|
||||
if (provider == null || constructor == null || !constructor.hasParameters()) {
|
||||
return EMPTY_ARRAY;
|
||||
}
|
||||
return constructor.map(it -> {
|
||||
|
||||
List<Object> params = new ArrayList<Object>();
|
||||
if (provider == null || !it.hasParameters()) {
|
||||
return EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
for (Parameter<?, P> parameter : constructor.getParameters()) {
|
||||
params.add(provider.getParameterValue(parameter));
|
||||
}
|
||||
return it.getParameters().stream()//
|
||||
.map(parameter -> provider.getParameterValue(parameter))//
|
||||
.toArray();
|
||||
|
||||
return params.toArray();
|
||||
}).orElse(EMPTY_ARRAY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,26 +362,31 @@ public class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
mv.visitTypeInsn(NEW, entityTypeResourcePath);
|
||||
mv.visitInsn(DUP);
|
||||
|
||||
Constructor<?> ctor = entity.getPersistenceConstructor().getConstructor();
|
||||
Class<?>[] parameterTypes = ctor.getParameterTypes();
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
entity.getPersistenceConstructor().ifPresent(constructor -> {
|
||||
|
||||
visitArrayIndex(mv, i);
|
||||
Constructor<?> ctor = constructor.getConstructor();
|
||||
Class<?>[] parameterTypes = ctor.getParameterTypes();
|
||||
|
||||
mv.visitInsn(AALOAD);
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
|
||||
if (parameterTypes[i].isPrimitive()) {
|
||||
insertUnboxInsns(mv, Type.getType(parameterTypes[i]).toString().charAt(0), "");
|
||||
} else {
|
||||
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(parameterTypes[i]));
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
|
||||
visitArrayIndex(mv, i);
|
||||
|
||||
mv.visitInsn(AALOAD);
|
||||
|
||||
if (parameterTypes[i].isPrimitive()) {
|
||||
insertUnboxInsns(mv, Type.getType(parameterTypes[i]).toString().charAt(0), "");
|
||||
} else {
|
||||
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(parameterTypes[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
mv.visitMethodInsn(INVOKESPECIAL, entityTypeResourcePath, INIT, Type.getConstructorDescriptor(ctor), false);
|
||||
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(0, 0); // (0, 0) = computed via ClassWriter.COMPUTE_MAXS
|
||||
mv.visitEnd();
|
||||
mv.visitMethodInsn(INVOKESPECIAL, entityTypeResourcePath, INIT, Type.getConstructorDescriptor(ctor), false);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(0, 0); // (0, 0) = computed via ClassWriter.COMPUTE_MAXS
|
||||
mv.visitEnd();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,6 +61,9 @@ public abstract class JodaTimeConverters {
|
||||
converters.add(DateToDateTimeConverter.INSTANCE);
|
||||
converters.add(DateToDateMidnightConverter.INSTANCE);
|
||||
|
||||
converters.add(LocalDateTimeToJodaLocalDateTime.INSTANCE);
|
||||
converters.add(LocalDateTimeToJodaDateTime.INSTANCE);
|
||||
|
||||
return converters;
|
||||
}
|
||||
|
||||
@@ -135,4 +138,36 @@ public abstract class JodaTimeConverters {
|
||||
return source == null ? null : new DateMidnight(source.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
public static enum LocalDateTimeToJodaLocalDateTime implements Converter<java.time.LocalDateTime, LocalDateTime> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public LocalDateTime convert(java.time.LocalDateTime source) {
|
||||
return source == null ? null
|
||||
: LocalDateTime.fromDateFields(
|
||||
org.springframework.data.convert.Jsr310Converters.LocalDateTimeToDateConverter.INSTANCE.convert(source));
|
||||
}
|
||||
}
|
||||
|
||||
public static enum LocalDateTimeToJodaDateTime implements Converter<java.time.LocalDateTime, DateTime> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public DateTime convert(java.time.LocalDateTime source) {
|
||||
return source == null ? null
|
||||
: new DateTime(
|
||||
org.springframework.data.convert.Jsr310Converters.LocalDateTimeToDateConverter.INSTANCE.convert(source));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,16 +16,16 @@
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.BeanInstantiationException;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.data.mapping.model.MappingInstantiationException;
|
||||
import org.springframework.data.mapping.model.ParameterValueProvider;
|
||||
|
||||
@@ -43,39 +43,45 @@ public enum ReflectionEntityInstantiator implements EntityInstantiator {
|
||||
public <T, E extends PersistentEntity<? extends T, P>, P extends PersistentProperty<P>> T createInstance(E entity,
|
||||
ParameterValueProvider<P> provider) {
|
||||
|
||||
PreferredConstructor<? extends T, P> constructor = entity.getPersistenceConstructor();
|
||||
return entity.getPersistenceConstructor().map(constructor -> {
|
||||
|
||||
if (constructor == null) {
|
||||
List<Object> params = Optional.ofNullable(provider)//
|
||||
.map(it -> constructor.getParameters().stream()//
|
||||
.map(parameter -> it.getParameterValue(parameter).orElse(null))//
|
||||
.collect(Collectors.toList()))//
|
||||
.orElse(Collections.emptyList());
|
||||
|
||||
try {
|
||||
Class<?> clazz = entity.getType();
|
||||
return (T) BeanUtils.instantiateClass(constructor.getConstructor(), params.toArray());
|
||||
} catch (BeanInstantiationException e) {
|
||||
throw new MappingInstantiationException(Optional.of(entity), params, e);
|
||||
}
|
||||
|
||||
}).orElseGet(() -> {
|
||||
|
||||
try {
|
||||
|
||||
Class<? extends T> clazz = entity.getType();
|
||||
|
||||
if (clazz.isArray()) {
|
||||
|
||||
Class<?> ctype = clazz;
|
||||
int dims = 0;
|
||||
|
||||
while (ctype.isArray()) {
|
||||
ctype = ctype.getComponentType();
|
||||
dims++;
|
||||
}
|
||||
|
||||
return (T) Array.newInstance(clazz, dims);
|
||||
|
||||
} else {
|
||||
return BeanUtils.instantiateClass(entity.getType());
|
||||
return BeanUtils.instantiateClass(clazz);
|
||||
}
|
||||
|
||||
} catch (BeanInstantiationException e) {
|
||||
throw new MappingInstantiationException(entity, Collections.emptyList(), e);
|
||||
throw new MappingInstantiationException(Optional.of(entity), Collections.emptyList(), e);
|
||||
}
|
||||
}
|
||||
|
||||
List<Object> params = new ArrayList<Object>();
|
||||
if (null != provider && constructor.hasParameters()) {
|
||||
for (Parameter<?, P> parameter : constructor.getParameters()) {
|
||||
params.add(provider.getParameterValue(parameter));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return BeanUtils.instantiateClass(constructor.getConstructor(), params.toArray());
|
||||
} catch (BeanInstantiationException e) {
|
||||
throw new MappingInstantiationException(entity, params, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,4 +186,5 @@ public abstract class ThreeTenBackPortConverters {
|
||||
return ZoneId.of(source);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user