/*
* Copyright 2016-2017 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.mapping.model;
import static org.assertj.core.api.Assertions.*;
import lombok.Data;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.springframework.data.annotation.AccessType;
import org.springframework.data.annotation.AccessType.Type;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.context.SampleMappingContext;
import org.springframework.data.mapping.context.SamplePersistentProperty;
import org.springframework.test.util.ReflectionTestUtils;
/**
* Unit tests for {@link ClassGeneratingPropertyAccessorFactory}
*
* @author Mark Paluch
* @author Oliver Gierke
*/
@RunWith(Parameterized.class)
public class ClassGeneratingPropertyAccessorFactoryDatatypeTests {
private final ClassGeneratingPropertyAccessorFactory factory = new ClassGeneratingPropertyAccessorFactory();
private final SampleMappingContext mappingContext = new SampleMappingContext();
private final Object bean;
private final String propertyName;
private final Optional<Object> value;
public ClassGeneratingPropertyAccessorFactoryDatatypeTests(Object bean, String propertyName, Object value,
String displayName) {
this.bean = bean;
this.propertyName = propertyName;
this.value = Optional.of(value);
}
@Parameters(name = "{3}")
public static List<Object[]> parameters() throws Exception {
List<Object[]> parameters = new ArrayList<>();
List<Class<?>> types = Arrays.asList(FieldAccess.class, PropertyAccess.class, PrivateFinalFieldAccess.class,
PrivateFinalPropertyAccess.class);
parameters.addAll(parameters(types, "primitiveInteger", Integer.valueOf(1)));
parameters.addAll(parameters(types, "primitiveIntegerArray", new int[] { 1, 2, 3 }));
parameters.addAll(parameters(types, "boxedInteger", Integer.valueOf(1)));
parameters.addAll(parameters(types, "boxedIntegerArray", new Integer[] { Integer.valueOf(1) }));
parameters.addAll(parameters(types, "primitiveShort", Short.valueOf("1")));
parameters.addAll(parameters(types, "primitiveShortArray", new short[] { 1, 2, 3 }));
parameters.addAll(parameters(types, "boxedShort", Short.valueOf("1")));
parameters.addAll(parameters(types, "boxedShortArray", new Short[] { Short.valueOf("1") }));
parameters.addAll(parameters(types, "primitiveByte", Byte.valueOf("1")));
parameters.addAll(parameters(types, "primitiveByteArray", new byte[] { 1, 2, 3 }));
parameters.addAll(parameters(types, "boxedByte", Byte.valueOf("1")));
parameters.addAll(parameters(types, "boxedByteArray", new Byte[] { Byte.valueOf("1") }));
parameters.addAll(parameters(types, "primitiveChar", Character.valueOf('c')));
parameters.addAll(parameters(types, "primitiveCharArray", new char[] { 'a', 'b', 'c' }));
parameters.addAll(parameters(types, "boxedChar", Character.valueOf('c')));
parameters.addAll(parameters(types, "boxedCharArray", new Character[] { Character.valueOf('c') }));
parameters.addAll(parameters(types, "primitiveBoolean", Boolean.valueOf(true)));
parameters.addAll(parameters(types, "primitiveBooleanArray", new boolean[] { true, false }));
parameters.addAll(parameters(types, "boxedBoolean", Boolean.valueOf(true)));
parameters.addAll(parameters(types, "boxedBooleanArray", new Boolean[] { Boolean.valueOf(true) }));
parameters.addAll(parameters(types, "primitiveFloat", Float.valueOf(1f)));
parameters.addAll(parameters(types, "primitiveFloatArray", new float[] { 1f, 2f }));
parameters.addAll(parameters(types, "boxedFloat", Float.valueOf(1f)));
parameters.addAll(parameters(types, "boxedFloatArray", new Float[] { Float.valueOf(1f) }));
parameters.addAll(parameters(types, "primitiveDouble", Double.valueOf(1d)));
parameters.addAll(parameters(types, "primitiveDoubleArray", new double[] { 1d, 2d }));
parameters.addAll(parameters(types, "boxedDouble", Double.valueOf(1d)));
parameters.addAll(parameters(types, "boxedDoubleArray", new Double[] { Double.valueOf(1d) }));
parameters.addAll(parameters(types, "primitiveLong", Long.valueOf(1L)));
parameters.addAll(parameters(types, "primitiveLongArray", new long[] { 1L, 2L }));
parameters.addAll(parameters(types, "boxedLong", Long.valueOf(1L)));
parameters.addAll(parameters(types, "boxedLongArray", new Long[] { Long.valueOf(1L) }));
parameters.addAll(parameters(types, "string", "hello"));
parameters.addAll(parameters(types, "stringArray", new String[] { "hello", "world" }));
return parameters;
}
private static List<Object[]> parameters(List<Class<?>> types, String propertyName, Object value) throws Exception {
List<Object[]> parameters = new ArrayList<>();
for (Class<?> type : types) {
Constructor<?>[] constructors = type.getDeclaredConstructors();
constructors[0].setAccessible(true);
parameters.add(new Object[] { constructors[0].newInstance(), propertyName, value,
type.getSimpleName() + "/" + propertyName });
}
return parameters;
}
@Test // DATACMNS-809
public void shouldSetAndGetProperty() throws Exception {
assertThat(getProperty(bean, propertyName)).hasValueSatisfying(property -> {
PersistentPropertyAccessor persistentPropertyAccessor = getPersistentPropertyAccessor(bean);
persistentPropertyAccessor.setProperty(property, value);
assertThat(persistentPropertyAccessor.getProperty(property)).isEqualTo(value);
});
}
@Test // DATACMNS-809
public void shouldUseClassPropertyAccessorFactory() throws Exception {
BasicPersistentEntity<Object, SamplePersistentProperty> persistentEntity = mappingContext
.getRequiredPersistentEntity(bean.getClass());
assertThat(ReflectionTestUtils.getField(persistentEntity, "propertyAccessorFactory"))
.isInstanceOf(ClassGeneratingPropertyAccessorFactory.class);
}
private PersistentPropertyAccessor getPersistentPropertyAccessor(Object bean) {
return factory.getPropertyAccessor(mappingContext.getRequiredPersistentEntity(bean.getClass()), bean);
}
private Optional<? extends PersistentProperty<?>> getProperty(Object bean, String name) {
BasicPersistentEntity<Object, SamplePersistentProperty> persistentEntity = mappingContext
.getRequiredPersistentEntity(bean.getClass());
return persistentEntity.getPersistentProperty(name);
}
// DATACMNS-809
@AccessType(Type.FIELD)
public static class FieldAccess {
int primitiveInteger;
int primitiveIntegerArray[];
Integer boxedInteger;
Integer boxedIntegerArray[];
short primitiveShort;
short primitiveShortArray[];
Short boxedShort;
Short boxedShortArray[];
byte primitiveByte;
byte primitiveByteArray[];
Byte boxedByte;
Byte boxedByteArray[];
char primitiveChar;
char primitiveCharArray[];
Character boxedChar;
Character boxedCharArray[];
boolean primitiveBoolean;
boolean primitiveBooleanArray[];
Boolean boxedBoolean;
Boolean boxedBooleanArray[];
float primitiveFloat;
float primitiveFloatArray[];
Float boxedFloat;
Float boxedFloatArray[];
double primitiveDouble;
double primitiveDoubleArray[];
Double boxedDouble;
Double boxedDoubleArray[];
long primitiveLong;
long primitiveLongArray[];
Long boxedLong;
Long boxedLongArray[];
String string;
String stringArray[];
}
// DATACMNS-809
@AccessType(Type.PROPERTY)
@Data
public static class PropertyAccess {
int primitiveInteger;
int primitiveIntegerArray[];
Integer boxedInteger;
Integer boxedIntegerArray[];
short primitiveShort;
short primitiveShortArray[];
Short boxedShort;
Short boxedShortArray[];
byte primitiveByte;
byte primitiveByteArray[];
Byte boxedByte;
Byte boxedByteArray[];
char primitiveChar;
char primitiveCharArray[];
Character boxedChar;
Character boxedCharArray[];
boolean primitiveBoolean;
boolean primitiveBooleanArray[];
Boolean boxedBoolean;
Boolean boxedBooleanArray[];
float primitiveFloat;
float primitiveFloatArray[];
Float boxedFloat;
Float boxedFloatArray[];
double primitiveDouble;
double primitiveDoubleArray[];
Double boxedDouble;
Double boxedDoubleArray[];
long primitiveLong;
long primitiveLongArray[];
Long boxedLong;
Long boxedLongArray[];
String string;
String stringArray[];
}
// DATACMNS-916
@AccessType(Type.FIELD)
private final static class PrivateFinalFieldAccess {
int primitiveInteger;
int primitiveIntegerArray[];
Integer boxedInteger;
Integer boxedIntegerArray[];
short primitiveShort;
short primitiveShortArray[];
Short boxedShort;
Short boxedShortArray[];
byte primitiveByte;
byte primitiveByteArray[];
Byte boxedByte;
Byte boxedByteArray[];
char primitiveChar;
char primitiveCharArray[];
Character boxedChar;
Character boxedCharArray[];
boolean primitiveBoolean;
boolean primitiveBooleanArray[];
Boolean boxedBoolean;
Boolean boxedBooleanArray[];
float primitiveFloat;
float primitiveFloatArray[];
Float boxedFloat;
Float boxedFloatArray[];
double primitiveDouble;
double primitiveDoubleArray[];
Double boxedDouble;
Double boxedDoubleArray[];
long primitiveLong;
long primitiveLongArray[];
Long boxedLong;
Long boxedLongArray[];
String string;
String stringArray[];
}
// DATACMNS-916
@AccessType(Type.PROPERTY)
@Data
private final static class PrivateFinalPropertyAccess {
int primitiveInteger;
int primitiveIntegerArray[];
Integer boxedInteger;
Integer boxedIntegerArray[];
short primitiveShort;
short primitiveShortArray[];
Short boxedShort;
Short boxedShortArray[];
byte primitiveByte;
byte primitiveByteArray[];
Byte boxedByte;
Byte boxedByteArray[];
char primitiveChar;
char primitiveCharArray[];
Character boxedChar;
Character boxedCharArray[];
boolean primitiveBoolean;
boolean primitiveBooleanArray[];
Boolean boxedBoolean;
Boolean boxedBooleanArray[];
float primitiveFloat;
float primitiveFloatArray[];
Float boxedFloat;
Float boxedFloatArray[];
double primitiveDouble;
double primitiveDoubleArray[];
Double boxedDouble;
Double boxedDoubleArray[];
long primitiveLong;
long primitiveLongArray[];
Long boxedLong;
Long boxedLongArray[];
String string;
String stringArray[];
}
}