Browse Source

DATACMNS-809 - Add Class-generating property accessor factory.

We now support generated PersistentPropertyAccessors when using Java 7 and if property/association name hashCodes are unique within a PersistentEntity.
Generated PersistentPropertyAccessors provide optimized access to properties. They use either MethodHandles or direct property/field access, depending on the visibility/final modifiers of the entity type and its members. A generated PersistentPropertyAccessor is injected into the originating class loader of the entity class to enable optimizations for package-default/protected member access.

Original pull request: #159.
pull/160/head
Mark Paluch 10 years ago committed by Oliver Gierke
parent
commit
899a98c83e
  1. 60
      src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java
  2. 1430
      src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java
  3. 45
      src/main/java/org/springframework/data/mapping/model/DefaultPersistentPropertyAccessorFactory.java
  4. 38
      src/main/java/org/springframework/data/mapping/model/PersistentPropertyAccessorFactory.java
  5. 25
      src/test/java/org/springframework/data/mapping/model/BasicPersistentEntityUnitTests.java
  6. 247
      src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactoryDatatypeTests.java
  7. 433
      src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactoryTests.java
  8. 83
      src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorPackageDefaultType.java
  9. 94
      src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorPublicType.java
  10. 82
      src/test/java/org/springframework/data/mapping/model/subpackage/TypeInOtherPackage.java

60
src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java

@ -45,12 +45,13 @@ import org.springframework.util.StringUtils; @@ -45,12 +45,13 @@ import org.springframework.util.StringUtils;
/**
* Simple value object to capture information of {@link PersistentEntity}s.
*
*
* @author Oliver Gierke
* @author Jon Brisbin
* @author Patryk Wasik
* @author Thomas Darimont
* @author Christoph Strobl
* @author Mark Paluch
*/
public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implements MutablePersistentEntity<T, P> {
@ -66,9 +67,11 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -66,9 +67,11 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
private P idProperty;
private P versionProperty;
private final PersistentPropertyAccessorFactory propertyAccessorFactory;
/**
* Creates a new {@link BasicPersistentEntity} from the given {@link TypeInformation}.
*
*
* @param information must not be {@literal null}.
*/
public BasicPersistentEntity(TypeInformation<T> information) {
@ -79,7 +82,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -79,7 +82,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
* Creates a new {@link BasicPersistentEntity} for the given {@link TypeInformation} and {@link Comparator}. The given
* {@link Comparator} will be used to define the order of the {@link PersistentProperty} instances added to the
* entity.
*
*
* @param information must not be {@literal null}.
* @param comparator can be {@literal null}.
*/
@ -91,14 +94,15 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -91,14 +94,15 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
this.properties = new ArrayList<P>();
this.comparator = comparator;
this.constructor = new PreferredConstructorDiscoverer<T, P>(information, this).getConstructor();
this.associations = comparator == null ? new HashSet<Association<P>>() : new TreeSet<Association<P>>(
new AssociationComparator<P>(comparator));
this.associations = comparator == null ? new HashSet<Association<P>>()
: new TreeSet<Association<P>>(new AssociationComparator<P>(comparator));
this.propertyCache = new HashMap<String, P>();
this.annotationCache = new HashMap<Class<? extends Annotation>, Annotation>();
this.propertyAccessorFactory = new DefaultPersistentPropertyAccessorFactory();
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.PersistentEntity#getPersistenceConstructor()
*/
@ -122,7 +126,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -122,7 +126,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
return this.idProperty == null ? false : this.idProperty.equals(property);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.PersistentEntity#isVersionProperty(org.springframework.data.mapping.PersistentProperty)
*/
@ -146,7 +150,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -146,7 +150,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
return idProperty;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.PersistentEntity#getVersionProperty()
*/
@ -154,7 +158,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -154,7 +158,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
return versionProperty;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.PersistentEntity#hasIdProperty()
*/
@ -162,7 +166,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -162,7 +166,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
return idProperty != null;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.PersistentEntity#hasVersionProperty()
*/
@ -170,7 +174,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -170,7 +174,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
return versionProperty != null;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.MutablePersistentEntity#addPersistentProperty(P)
*/
@ -197,9 +201,11 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -197,9 +201,11 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
if (property.isVersionProperty()) {
if (this.versionProperty != null) {
throw new MappingException(String.format(
"Attempt to add version property %s but already have property %s registered "
+ "as version. Check your mapping configuration!", property.getField(), versionProperty.getField()));
throw new MappingException(
String.format(
"Attempt to add version property %s but already have property %s registered "
+ "as version. Check your mapping configuration!",
property.getField(), versionProperty.getField()));
}
this.versionProperty = property;
@ -208,7 +214,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -208,7 +214,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
/**
* Returns the given property if it is a better candidate for the id property than the current id property.
*
*
* @param property the new id property candidate, will never be {@literal null}.
* @return the given id property or {@literal null} if the given property is not an id property.
*/
@ -244,7 +250,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -244,7 +250,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
return propertyCache.get(name);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.PersistentEntity#getPersistentProperty(java.lang.Class)
*/
@ -279,7 +285,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -279,7 +285,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
return information.getType();
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.PersistentEntity#getTypeAlias()
*/
@ -312,7 +318,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -312,7 +318,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.PersistentEntity#doWithProperties(org.springframework.data.mapping.PropertyHandler.Simple)
*/
@ -354,7 +360,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -354,7 +360,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.PersistentEntity#findAnnotation(java.lang.Class)
*/
@ -372,7 +378,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -372,7 +378,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
return annotation;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.MutablePersistentEntity#verify()
*/
@ -383,7 +389,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -383,7 +389,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.PersistentEntity#getPropertyAccessor(java.lang.Object)
*/
@ -393,10 +399,10 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -393,10 +399,10 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
Assert.notNull(bean, "Target bean must not be null!");
Assert.isTrue(getType().isInstance(bean), "Target bean is not of type of the persistent entity!");
return new BeanWrapper<Object>(bean);
return propertyAccessorFactory.getPropertyAccessor(this, bean);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.PersistentEntity#getIdentifierAccessor(java.lang.Object)
*/
@ -419,7 +425,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -419,7 +425,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
INSTANCE;
/*
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.IdentifierAccessor#getIdentifier()
*/
@ -431,11 +437,11 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement @@ -431,11 +437,11 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
/**
* Simple {@link Comparator} adaptor to delegate ordering to the inverse properties of the association.
*
*
* @author Oliver Gierke
*/
private static final class AssociationComparator<P extends PersistentProperty<P>> implements
Comparator<Association<P>>, Serializable {
private static final class AssociationComparator<P extends PersistentProperty<P>>
implements Comparator<Association<P>>, Serializable {
private static final long serialVersionUID = 4508054194886854513L;
private final Comparator<P> delegate;

1430
src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java

File diff suppressed because it is too large Load Diff

45
src/main/java/org/springframework/data/mapping/model/DefaultPersistentPropertyAccessorFactory.java

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
/*
* Copyright 2016 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 org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentPropertyAccessor;
/**
* Default implementation of {@link PersistentPropertyAccessorFactory}. Accessors can access bean properties either via
* reflection or use generated classes with direct field/method access.
*
* @author Mark Paluch
* @since 1.13
*/
public class DefaultPersistentPropertyAccessorFactory implements PersistentPropertyAccessorFactory {
private final ClassGeneratingPropertyAccessorFactory classGeneratingPropertyAccessorFactory = new ClassGeneratingPropertyAccessorFactory();
/* (non-Javadoc)
* @see org.springframework.data.mapping.model.PersistentPropertyAccessorFactory#getPropertyAccessor(org.springframework.data.mapping.PersistentEntity, java.lang.Object)
*/
@Override
public PersistentPropertyAccessor getPropertyAccessor(PersistentEntity<?, ?> entity, Object bean) {
if (ClassGeneratingPropertyAccessorFactory.canGenerateAccessorClass(entity)) {
return classGeneratingPropertyAccessorFactory.getPropertyAccessor(entity, bean);
}
return new BeanWrapper<Object>(bean);
}
}

38
src/main/java/org/springframework/data/mapping/model/PersistentPropertyAccessorFactory.java

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
/*
* Copyright 2016 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 org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentPropertyAccessor;
/**
* Factory to create {@link PersistentPropertyAccessor} for a given {@link PersistentEntity} and {@code bean}.
*
* @author Mark Paluch
* @since 1.13
*/
public interface PersistentPropertyAccessorFactory {
/**
* Returns a {@link PersistentPropertyAccessor} for a given {@link PersistentEntity} and {@code bean}.
*
* @param bean
* @return
*/
PersistentPropertyAccessor getPropertyAccessor(PersistentEntity<?, ?> entity, Object bean);
}

25
src/test/java/org/springframework/data/mapping/model/BasicPersistentEntityUnitTests.java

@ -17,6 +17,7 @@ package org.springframework.data.mapping.model; @@ -17,6 +17,7 @@ package org.springframework.data.mapping.model;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.junit.Assume.assumeThat;
import static org.mockito.Mockito.*;
import java.lang.annotation.Retention;
@ -25,6 +26,7 @@ import java.util.Comparator; @@ -25,6 +26,7 @@ import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import org.hamcrest.CoreMatchers;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@ -49,7 +51,7 @@ import org.springframework.test.util.ReflectionTestUtils; @@ -49,7 +51,7 @@ import org.springframework.test.util.ReflectionTestUtils;
/**
* Unit test for {@link BasicPersistentEntity}.
*
*
* @author Oliver Gierke
* @author Christoph Strobl
*/
@ -181,6 +183,8 @@ public class BasicPersistentEntityUnitTests<T extends PersistentProperty<T>> { @@ -181,6 +183,8 @@ public class BasicPersistentEntityUnitTests<T extends PersistentProperty<T>> {
@Test
public void returnsBeanWrapperForPropertyAccessor() {
assumeThat(System.getProperty("java.version"), CoreMatchers.startsWith("1.6"));
SampleMappingContext context = new SampleMappingContext();
PersistentEntity<Object, SamplePersistentProperty> entity = context.getPersistentEntity(Entity.class);
@ -191,6 +195,25 @@ public class BasicPersistentEntityUnitTests<T extends PersistentProperty<T>> { @@ -191,6 +195,25 @@ public class BasicPersistentEntityUnitTests<T extends PersistentProperty<T>> {
assertThat(accessor.getBean(), is((Object) value));
}
/**
* @see DATACMNS-809
*/
@Test
public void returnsGeneratedPropertyAccessorForPropertyAccessor() {
assumeThat(System.getProperty("java.version"), not(CoreMatchers.startsWith("1.6")));
SampleMappingContext context = new SampleMappingContext();
PersistentEntity<Object, SamplePersistentProperty> entity = context.getPersistentEntity(Entity.class);
Entity value = new Entity();
PersistentPropertyAccessor accessor = entity.getPropertyAccessor(value);
assertThat(accessor, is(not(instanceOf(BeanWrapper.class))));
assertThat(accessor.getClass().getName(), containsString("_Accessor_"));
assertThat(accessor.getBean(), is((Object) value));
}
/**
* @see DATACMNS-596
*/

247
src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactoryDatatypeTests.java

@ -0,0 +1,247 @@ @@ -0,0 +1,247 @@
/*
* Copyright 2016 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.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
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 lombok.Data;
/**
* Unit tests for {@link ClassGeneratingPropertyAccessorFactory}
*
* @author Mark Paluch
* @see DATACMNS-809
*/
@RunWith(Parameterized.class)
public class ClassGeneratingPropertyAccessorFactoryDatatypeTests {
private final ClassGeneratingPropertyAccessorFactory factory = new ClassGeneratingPropertyAccessorFactory();
private final SampleMappingContext mappingContext = new SampleMappingContext();
private Object bean;
private String propertyName;
private Object value;
public ClassGeneratingPropertyAccessorFactoryDatatypeTests(Object bean, String propertyName, Object value,
String displayName) {
this.bean = bean;
this.propertyName = propertyName;
this.value = value;
}
@Parameters(name = "{3}")
public static List<Object[]> parameters() throws Exception {
List<Object[]> parameters = new ArrayList<Object[]>();
List<Class<?>> types = Arrays.asList(FieldAccess.class, PropertyAccess.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<Object[]>();
for (Class<?> type : types) {
parameters
.add(new Object[] { type.newInstance(), propertyName, value, type.getSimpleName() + "/" + propertyName });
}
return parameters;
}
/**
* @see DATACMNS-809
* @throws Exception
*/
@Test
public void shouldSetAndGetProperty() throws Exception {
PersistentProperty<?> property = getProperty(bean, propertyName);
PersistentPropertyAccessor persistentPropertyAccessor = getPersistentPropertyAccessor(bean);
persistentPropertyAccessor.setProperty(property, value);
assertThat(persistentPropertyAccessor.getProperty(property), is(equalTo((Object) value)));
}
private PersistentPropertyAccessor getPersistentPropertyAccessor(Object bean) {
return factory.getPropertyAccessor(mappingContext.getPersistentEntity(bean.getClass()), bean);
}
private PersistentProperty<?> getProperty(Object bean, String name) {
BasicPersistentEntity<Object, SamplePersistentProperty> persistentEntity = mappingContext
.getPersistentEntity(bean.getClass());
return persistentEntity.getPersistentProperty(name);
}
/**
* @see 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[];
}
/**
* @see 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[];
}
}

433
src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactoryTests.java

@ -0,0 +1,433 @@ @@ -0,0 +1,433 @@
/*
* Copyright 2016 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.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.*;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
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.data.mapping.model.subpackage.TypeInOtherPackage;
/**
* Unit tests for {@link ClassGeneratingPropertyAccessorFactory}
*
* @author Mark Paluch
* @see DATACMNS-809
*/
@RunWith(Parameterized.class)
public class ClassGeneratingPropertyAccessorFactoryTests {
private final ClassGeneratingPropertyAccessorFactory factory = new ClassGeneratingPropertyAccessorFactory();
private final SampleMappingContext mappingContext = new SampleMappingContext();
private Object bean;
private String propertyName;
private Class<?> expectedConstructorType;
public ClassGeneratingPropertyAccessorFactoryTests(Object bean, String propertyName, Class<?> expectedConstructorType,
String displayName) {
this.bean = bean;
this.propertyName = propertyName;
this.expectedConstructorType = expectedConstructorType;
}
@Parameters(name = "{3}")
public static List<Object[]> parameters() {
List<Object[]> parameters = new ArrayList<Object[]>();
List<String> propertyNames = Arrays.asList("privateField", "packageDefaultField", "protectedField", "publicField",
"privateProperty", "packageDefaultProperty", "protectedProperty", "publicProperty", "syntheticProperty");
parameters.addAll(parameters(new InnerPrivateType(), propertyNames, Object.class));
parameters.addAll(parameters(new InnerTypeWithPrivateAncesor(), propertyNames, InnerTypeWithPrivateAncesor.class));
parameters.addAll(parameters(new InnerPackageDefaultType(), propertyNames, InnerPackageDefaultType.class));
parameters.addAll(parameters(new InnerProtectedType(), propertyNames, InnerProtectedType.class));
parameters.addAll(parameters(new InnerPublicType(), propertyNames, InnerPublicType.class));
parameters.addAll(parameters(new ClassGeneratingPropertyAccessorPackageDefaultType(), propertyNames,
ClassGeneratingPropertyAccessorPackageDefaultType.class));
parameters.addAll(parameters(new ClassGeneratingPropertyAccessorPublicType(), propertyNames,
ClassGeneratingPropertyAccessorPublicType.class));
parameters.addAll(parameters(new SubtypeOfTypeInOtherPackage(), propertyNames,
SubtypeOfTypeInOtherPackage.class));
return parameters;
}
private static List<Object[]> parameters(Object bean, List<String> propertyNames, Class<?> expectedConstructorType) {
List<Object[]> parameters = new ArrayList<Object[]>();
for (String propertyName : propertyNames) {
parameters.add(new Object[] { bean, propertyName, expectedConstructorType,
bean.getClass().getSimpleName() + "/" + propertyName });
}
return parameters;
}
/**
* @see DATACMNS-809
* @throws Exception
*/
@Test
public void shouldSetAndGetProperty() throws Exception {
PersistentProperty<?> property = getProperty(bean, propertyName);
PersistentPropertyAccessor persistentPropertyAccessor = getPersistentPropertyAccessor(bean);
persistentPropertyAccessor.setProperty(property, "value");
assertThat(persistentPropertyAccessor.getProperty(property), is(equalTo((Object) "value")));
}
/**
* @see DATACMNS-809
* @throws Exception
*/
@Test
public void accessorShouldDeclareConstructor() throws Exception {
PersistentPropertyAccessor persistentPropertyAccessor = getPersistentPropertyAccessor(bean);
Constructor<?>[] declaredConstructors = persistentPropertyAccessor.getClass().getDeclaredConstructors();
assertThat(declaredConstructors.length, is(1));
assertThat(declaredConstructors[0].getParameterTypes().length, is(1));
assertThat(declaredConstructors[0].getParameterTypes()[0], is(equalTo((Class) expectedConstructorType)));
}
/**
* @see DATACMNS-809
*/
@Test(expected = IllegalArgumentException.class)
public void shouldFailOnNullBean() {
factory.getPropertyAccessor(mappingContext.getPersistentEntity(bean.getClass()), null);
}
/**
* @see DATACMNS-809
*/
@Test(expected = UnsupportedOperationException.class)
public void getPropertyShouldFailOnUnhandledProperty() {
PersistentProperty<?> property = getProperty(new Dummy(), "dummy");
PersistentPropertyAccessor persistentPropertyAccessor = getPersistentPropertyAccessor(bean);
persistentPropertyAccessor.getProperty(property);
}
/**
* @see DATACMNS-809
*/
@Test(expected = UnsupportedOperationException.class)
public void setPropertyShouldFailOnUnhandledProperty() {
PersistentProperty<?> property = getProperty(new Dummy(), "dummy");
PersistentPropertyAccessor persistentPropertyAccessor = getPersistentPropertyAccessor(bean);
persistentPropertyAccessor.setProperty(property, null);
}
private PersistentPropertyAccessor getPersistentPropertyAccessor(Object bean) {
return factory.getPropertyAccessor(mappingContext.getPersistentEntity(bean.getClass()), bean);
}
private PersistentProperty<?> getProperty(Object bean, String name) {
BasicPersistentEntity<Object, SamplePersistentProperty> persistentEntity = mappingContext
.getPersistentEntity(bean.getClass());
return persistentEntity.getPersistentProperty(name);
}
/**
* @see DATACMNS-809
*/
private static class InnerPrivateType {
private String privateField;
String packageDefaultField;
protected String protectedField;
public String publicField;
private String backing;
@AccessType(Type.PROPERTY) private String privateProperty;
@AccessType(Type.PROPERTY) private String packageDefaultProperty;
@AccessType(Type.PROPERTY) private String protectedProperty;
@AccessType(Type.PROPERTY) private String publicProperty;
private String getPrivateProperty() {
return privateProperty;
}
private void setPrivateProperty(String privateProperty) {
this.privateProperty = privateProperty;
}
String getPackageDefaultProperty() {
return packageDefaultProperty;
}
void setPackageDefaultProperty(String packageDefaultProperty) {
this.packageDefaultProperty = packageDefaultProperty;
}
protected String getProtectedProperty() {
return protectedProperty;
}
protected void setProtectedProperty(String protectedProperty) {
this.protectedProperty = protectedProperty;
}
public String getPublicProperty() {
return publicProperty;
}
public void setPublicProperty(String publicProperty) {
this.publicProperty = publicProperty;
}
@AccessType(Type.PROPERTY)
public String getSyntheticProperty() {
return backing;
}
public void setSyntheticProperty(String syntheticProperty) {
backing = syntheticProperty;
}
}
/**
* @see DATACMNS-809
*/
public static class InnerTypeWithPrivateAncesor extends InnerPrivateType {
}
/**
* @see DATACMNS-809
*/
static class InnerPackageDefaultType {
private String privateField;
String packageDefaultField;
protected String protectedField;
public String publicField;
private String backing;
@AccessType(Type.PROPERTY) private String privateProperty;
@AccessType(Type.PROPERTY) private String packageDefaultProperty;
@AccessType(Type.PROPERTY) private String protectedProperty;
@AccessType(Type.PROPERTY) private String publicProperty;
private String getPrivateProperty() {
return privateProperty;
}
private void setPrivateProperty(String privateProperty) {
this.privateProperty = privateProperty;
}
String getPackageDefaultProperty() {
return packageDefaultProperty;
}
void setPackageDefaultProperty(String packageDefaultProperty) {
this.packageDefaultProperty = packageDefaultProperty;
}
protected String getProtectedProperty() {
return protectedProperty;
}
protected void setProtectedProperty(String protectedProperty) {
this.protectedProperty = protectedProperty;
}
public String getPublicProperty() {
return publicProperty;
}
public void setPublicProperty(String publicProperty) {
this.publicProperty = publicProperty;
}
@AccessType(Type.PROPERTY)
public String getSyntheticProperty() {
return backing;
}
public void setSyntheticProperty(String syntheticProperty) {
backing = syntheticProperty;
}
}
/**
* @see DATACMNS-809
*/
protected static class InnerProtectedType {
private String privateField;
String packageDefaultField;
protected String protectedField;
public String publicField;
private String backing;
@AccessType(Type.PROPERTY) private String privateProperty;
@AccessType(Type.PROPERTY) private String packageDefaultProperty;
@AccessType(Type.PROPERTY) private String protectedProperty;
@AccessType(Type.PROPERTY) private String publicProperty;
private String getPrivateProperty() {
return privateProperty;
}
private void setPrivateProperty(String privateProperty) {
this.privateProperty = privateProperty;
}
String getPackageDefaultProperty() {
return packageDefaultProperty;
}
void setPackageDefaultProperty(String packageDefaultProperty) {
this.packageDefaultProperty = packageDefaultProperty;
}
protected String getProtectedProperty() {
return protectedProperty;
}
protected void setProtectedProperty(String protectedProperty) {
this.protectedProperty = protectedProperty;
}
public String getPublicProperty() {
return publicProperty;
}
public void setPublicProperty(String publicProperty) {
this.publicProperty = publicProperty;
}
@AccessType(Type.PROPERTY)
public String getSyntheticProperty() {
return backing;
}
public void setSyntheticProperty(String syntheticProperty) {
backing = syntheticProperty;
}
}
/**
* @see DATACMNS-809
*/
public static class InnerPublicType {
private String privateField;
String packageDefaultField;
protected String protectedField;
public String publicField;
private String backing;
@AccessType(Type.PROPERTY) private String privateProperty;
@AccessType(Type.PROPERTY) private String packageDefaultProperty;
@AccessType(Type.PROPERTY) private String protectedProperty;
@AccessType(Type.PROPERTY) private String publicProperty;
private String getPrivateProperty() {
return privateProperty;
}
private void setPrivateProperty(String privateProperty) {
this.privateProperty = privateProperty;
}
String getPackageDefaultProperty() {
return packageDefaultProperty;
}
void setPackageDefaultProperty(String packageDefaultProperty) {
this.packageDefaultProperty = packageDefaultProperty;
}
protected String getProtectedProperty() {
return protectedProperty;
}
protected void setProtectedProperty(String protectedProperty) {
this.protectedProperty = protectedProperty;
}
public String getPublicProperty() {
return publicProperty;
}
public void setPublicProperty(String publicProperty) {
this.publicProperty = publicProperty;
}
@AccessType(Type.PROPERTY)
public String getSyntheticProperty() {
return backing;
}
public void setSyntheticProperty(String syntheticProperty) {
backing = syntheticProperty;
}
}
public static class SubtypeOfTypeInOtherPackage extends TypeInOtherPackage{
}
/**
* @see DATACMNS-809
*/
private static class Dummy {
private String dummy;
public String publicField;
}
}

83
src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorPackageDefaultType.java

@ -0,0 +1,83 @@ @@ -0,0 +1,83 @@
/*
* Copyright 2016 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 org.springframework.data.annotation.AccessType;
import org.springframework.data.annotation.AccessType.Type;
/**
* @author Mark Paluch
* @see DATACMNS-809
*/
class ClassGeneratingPropertyAccessorPackageDefaultType {
private String privateField;
String packageDefaultField;
protected String protectedField;
public String publicField;
private String backing;
@AccessType(Type.PROPERTY) private String privateProperty;
@AccessType(Type.PROPERTY) private String packageDefaultProperty;
@AccessType(Type.PROPERTY) private String protectedProperty;
@AccessType(Type.PROPERTY) private String publicProperty;
private String getPrivateProperty() {
return privateProperty;
}
private void setPrivateProperty(String privateProperty) {
this.privateProperty = privateProperty;
}
String getPackageDefaultProperty() {
return packageDefaultProperty;
}
void setPackageDefaultProperty(String packageDefaultProperty) {
this.packageDefaultProperty = packageDefaultProperty;
}
protected String getProtectedProperty() {
return protectedProperty;
}
protected void setProtectedProperty(String protectedProperty) {
this.protectedProperty = protectedProperty;
}
public String getPublicProperty() {
return publicProperty;
}
public void setPublicProperty(String publicProperty) {
this.publicProperty = publicProperty;
}
@AccessType(Type.PROPERTY)
public String getSyntheticProperty() {
return backing;
}
public void setSyntheticProperty(String syntheticProperty) {
backing = syntheticProperty;
}
}

94
src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorPublicType.java

@ -0,0 +1,94 @@ @@ -0,0 +1,94 @@
/*
* Copyright 2016 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 org.springframework.data.annotation.AccessType;
import org.springframework.data.annotation.AccessType.Type;
/**
* @author Mark Paluch
* @see DATACMNS-809
*/
public class ClassGeneratingPropertyAccessorPublicType {
private String privateField;
String packageDefaultField;
protected String protectedField;
public String publicField;
private String backing;
private Integer aa;
private int bb;
@AccessType(Type.PROPERTY) private String privateProperty;
@AccessType(Type.PROPERTY) private String packageDefaultProperty;
@AccessType(Type.PROPERTY) private String protectedProperty;
@AccessType(Type.PROPERTY) private String publicProperty;
private String getPrivateProperty() {
return privateProperty;
}
private void setPrivateProperty(String privateProperty) {
this.privateProperty = privateProperty;
}
String getPackageDefaultProperty() {
return packageDefaultProperty;
}
void setPackageDefaultProperty(String packageDefaultProperty) {
this.packageDefaultProperty = packageDefaultProperty;
}
protected String getProtectedProperty() {
return protectedProperty;
}
protected void setProtectedProperty(String protectedProperty) {
this.protectedProperty = protectedProperty;
}
public String getPublicProperty() {
return publicProperty;
}
public void setPublicProperty(String publicProperty) {
this.publicProperty = publicProperty;
}
@AccessType(Type.PROPERTY)
public String getSyntheticProperty() {
return backing;
}
public void setSyntheticProperty(String syntheticProperty) {
backing = syntheticProperty;
}
public Object set(Object e) {
aa = (Integer) e;
bb = (Integer) e;
return bb;
}
public static void main(String[] args) {
}
}

82
src/test/java/org/springframework/data/mapping/model/subpackage/TypeInOtherPackage.java

@ -0,0 +1,82 @@ @@ -0,0 +1,82 @@
/*
* Copyright 2016 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.subpackage;
import org.springframework.data.annotation.AccessType;
import org.springframework.data.annotation.AccessType.Type;
/**
* @author Mark Paluch
* @see DATACMNS-809
*/
public class TypeInOtherPackage {
private String privateField;
String packageDefaultField;
protected String protectedField;
public String publicField;
private String backing;
@AccessType(Type.PROPERTY) private String privateProperty;
@AccessType(Type.PROPERTY) private String packageDefaultProperty;
@AccessType(Type.PROPERTY) private String protectedProperty;
@AccessType(Type.PROPERTY) private String publicProperty;
private String getPrivateProperty() {
return privateProperty;
}
private void setPrivateProperty(String privateProperty) {
this.privateProperty = privateProperty;
}
String getPackageDefaultProperty() {
return packageDefaultProperty;
}
void setPackageDefaultProperty(String packageDefaultProperty) {
this.packageDefaultProperty = packageDefaultProperty;
}
protected String getProtectedProperty() {
return protectedProperty;
}
protected void setProtectedProperty(String protectedProperty) {
this.protectedProperty = protectedProperty;
}
public String getPublicProperty() {
return publicProperty;
}
public void setPublicProperty(String publicProperty) {
this.publicProperty = publicProperty;
}
@AccessType(Type.PROPERTY)
public String getSyntheticProperty() {
return backing;
}
public void setSyntheticProperty(String syntheticProperty) {
backing = syntheticProperty;
}
}
Loading…
Cancel
Save