DATACMNS-867 - First draft.

This commit is contained in:
Oliver Gierke
2016-11-14 20:10:22 +01:00
parent 1b17271915
commit cc63e5b7a4
278 changed files with 4737 additions and 5714 deletions

View File

@@ -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);
}
}

View File

@@ -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();
});
}
/**

View File

@@ -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));
}
}
}

View File

@@ -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);
}
});
}
}

View File

@@ -186,4 +186,5 @@ public abstract class ThreeTenBackPortConverters {
return ZoneId.of(source);
}
}
}