Skip to content

Commit 29ef67e

Browse files
committed
DATACMNS-809 - Support array properties and use MethodHandle access with cross-package types.
1 parent a4c6bf4 commit 29ef67e

File tree

4 files changed

+180
-128
lines changed

4 files changed

+180
-128
lines changed

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

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,19 @@ public PersistentPropertyAccessor getPropertyAccessor(PersistentEntity<?, ?> ent
9393
* Checks whether an accessor class can be generated.
9494
*
9595
* @param entity
96-
* @return true if the runtime is equal or greater to Java 1.7 and property name hash codes are unique.
96+
* @return true if the runtime is equal or greater to Java 1.7, property name hash codes are unique and the type has a
97+
* class loader we can use to re-inject types.
9798
*/
9899
public static boolean canGenerateAccessorClass(PersistentEntity<?, ?> entity) {
99100

100101
if (!IS_JAVA_JAVA_7) {
101102
return false;
102103
}
103104

105+
if (entity.getType().getClassLoader() == null || entity.getType().getPackage().getName().startsWith("java")) {
106+
return false;
107+
}
108+
104109
final Set<Integer> hashCodes = new HashSet<Integer>();
105110
final AtomicInteger propertyCount = new AtomicInteger();
106111
entity.doWithProperties(new SimplePropertyHandler() {
@@ -1117,13 +1122,38 @@ private boolean isAccessible(int modifiers) {
11171122
return true;
11181123
}
11191124

1125+
private boolean isDefault(int modifiers) {
1126+
1127+
if (Modifier.isPrivate(modifiers) || Modifier.isProtected(modifiers) || Modifier.isPublic(modifiers)) {
1128+
return false;
1129+
}
1130+
1131+
return true;
1132+
}
1133+
11201134
private boolean generateSetterMethodHandle(PersistentEntity<?, ?> entity, Field field) {
11211135
return generateMethodHandle(entity, field) || Modifier.isFinal(field.getModifiers());
11221136
}
11231137

1138+
/**
1139+
* Check whether to generate {@link java.lang.invoke.MethodHandle} access. Checks visibility rules of the member and
1140+
* its declaring class. Use also {@link java.lang.invoke.MethodHandle} if visibility is protected/package-default
1141+
* and packages of the declaring types are different.
1142+
*
1143+
* @param entity
1144+
* @param member
1145+
* @return
1146+
*/
11241147
private boolean generateMethodHandle(PersistentEntity<?, ?> entity, Member member) {
11251148

11261149
if (isAccessible(entity)) {
1150+
1151+
if (Modifier.isProtected(member.getModifiers()) || isDefault(member.getModifiers())) {
1152+
if (!member.getDeclaringClass().getPackage().equals(entity.getClass().getPackage())) {
1153+
return true;
1154+
}
1155+
}
1156+
11271157
if (isAccessible(member.getDeclaringClass()) && isAccessible(member.getModifiers())) {
11281158
return false;
11291159
}
@@ -1145,6 +1175,9 @@ private int classVariableIndex4(List<Class<?>> list, Class<?> item) {
11451175
}
11461176

11471177
private static String referenceName(Class<?> type) {
1178+
if (type.isArray()) {
1179+
return Type.getInternalName(type);
1180+
}
11481181
return referenceName(Type.getInternalName(type));
11491182
}
11501183

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

Lines changed: 57 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
import org.springframework.data.mapping.context.SampleMappingContext;
3636
import org.springframework.data.mapping.context.SamplePersistentProperty;
3737

38+
import lombok.Data;
39+
3840
/**
3941
* Unit tests for {@link ClassGeneratingPropertyAccessorFactory}
4042
*
@@ -67,21 +69,39 @@ public static List<Object[]> parameters() throws Exception {
6769
List<Class<?>> types = Arrays.asList(FieldAccess.class, PropertyAccess.class);
6870

6971
parameters.addAll(parameters(types, "primitiveInteger", Integer.valueOf(1)));
72+
parameters.addAll(parameters(types, "primitiveIntegerArray", new int[] { 1, 2, 3 }));
7073
parameters.addAll(parameters(types, "boxedInteger", Integer.valueOf(1)));
74+
parameters.addAll(parameters(types, "boxedIntegerArray", new Integer[] { Integer.valueOf(1) }));
7175
parameters.addAll(parameters(types, "primitiveShort", Short.valueOf("1")));
76+
parameters.addAll(parameters(types, "primitiveShortArray", new short[] { 1, 2, 3 }));
7277
parameters.addAll(parameters(types, "boxedShort", Short.valueOf("1")));
78+
parameters.addAll(parameters(types, "boxedShortArray", new Short[] { Short.valueOf("1") }));
7379
parameters.addAll(parameters(types, "primitiveByte", Byte.valueOf("1")));
80+
parameters.addAll(parameters(types, "primitiveByteArray", new byte[] { 1, 2, 3 }));
7481
parameters.addAll(parameters(types, "boxedByte", Byte.valueOf("1")));
82+
parameters.addAll(parameters(types, "boxedByteArray", new Byte[] { Byte.valueOf("1") }));
7583
parameters.addAll(parameters(types, "primitiveChar", Character.valueOf('c')));
84+
parameters.addAll(parameters(types, "primitiveCharArray", new char[] { 'a', 'b', 'c' }));
7685
parameters.addAll(parameters(types, "boxedChar", Character.valueOf('c')));
86+
parameters.addAll(parameters(types, "boxedCharArray", new Character[] { Character.valueOf('c') }));
7787
parameters.addAll(parameters(types, "primitiveBoolean", Boolean.valueOf(true)));
88+
parameters.addAll(parameters(types, "primitiveBooleanArray", new boolean[] { true, false }));
7889
parameters.addAll(parameters(types, "boxedBoolean", Boolean.valueOf(true)));
90+
parameters.addAll(parameters(types, "boxedBooleanArray", new Boolean[] { Boolean.valueOf(true) }));
7991
parameters.addAll(parameters(types, "primitiveFloat", Float.valueOf(1f)));
92+
parameters.addAll(parameters(types, "primitiveFloatArray", new float[] { 1f, 2f }));
8093
parameters.addAll(parameters(types, "boxedFloat", Float.valueOf(1f)));
94+
parameters.addAll(parameters(types, "boxedFloatArray", new Float[] { Float.valueOf(1f) }));
8195
parameters.addAll(parameters(types, "primitiveDouble", Double.valueOf(1d)));
96+
parameters.addAll(parameters(types, "primitiveDoubleArray", new double[] { 1d, 2d }));
8297
parameters.addAll(parameters(types, "boxedDouble", Double.valueOf(1d)));
98+
parameters.addAll(parameters(types, "boxedDoubleArray", new Double[] { Double.valueOf(1d) }));
8399
parameters.addAll(parameters(types, "primitiveLong", Long.valueOf(1L)));
100+
parameters.addAll(parameters(types, "primitiveLongArray", new long[] { 1L, 2L }));
84101
parameters.addAll(parameters(types, "boxedLong", Long.valueOf(1L)));
102+
parameters.addAll(parameters(types, "boxedLongArray", new Long[] { Long.valueOf(1L) }));
103+
parameters.addAll(parameters(types, "string", "hello"));
104+
parameters.addAll(parameters(types, "stringArray", new String[] { "hello", "world" }));
85105

86106
return parameters;
87107
}
@@ -130,188 +150,98 @@ private PersistentProperty<?> getProperty(Object bean, String name) {
130150
public static class FieldAccess {
131151

132152
int primitiveInteger;
153+
int primitiveIntegerArray[];
133154
Integer boxedInteger;
155+
Integer boxedIntegerArray[];
134156

135157
short primitiveShort;
158+
short primitiveShortArray[];
136159
Short boxedShort;
160+
Short boxedShortArray[];
137161

138162
byte primitiveByte;
163+
byte primitiveByteArray[];
139164
Byte boxedByte;
165+
Byte boxedByteArray[];
140166

141167
char primitiveChar;
168+
char primitiveCharArray[];
142169
Character boxedChar;
170+
Character boxedCharArray[];
143171

144172
boolean primitiveBoolean;
173+
boolean primitiveBooleanArray[];
145174
Boolean boxedBoolean;
175+
Boolean boxedBooleanArray[];
146176

147177
float primitiveFloat;
178+
float primitiveFloatArray[];
148179
Float boxedFloat;
180+
Float boxedFloatArray[];
149181

150182
double primitiveDouble;
183+
double primitiveDoubleArray[];
151184
Double boxedDouble;
185+
Double boxedDoubleArray[];
152186

153187
long primitiveLong;
188+
long primitiveLongArray[];
154189
Long boxedLong;
190+
Long boxedLongArray[];
155191

192+
String string;
193+
String stringArray[];
156194
}
157195

158196
/**
159197
* @see DATACMNS-809
160198
*/
161199
@AccessType(Type.PROPERTY)
200+
@Data
162201
public static class PropertyAccess {
163202

164203
int primitiveInteger;
204+
int primitiveIntegerArray[];
165205
Integer boxedInteger;
206+
Integer boxedIntegerArray[];
166207

167208
short primitiveShort;
209+
short primitiveShortArray[];
168210
Short boxedShort;
211+
Short boxedShortArray[];
169212

170213
byte primitiveByte;
214+
byte primitiveByteArray[];
171215
Byte boxedByte;
216+
Byte boxedByteArray[];
172217

173218
char primitiveChar;
219+
char primitiveCharArray[];
174220
Character boxedChar;
221+
Character boxedCharArray[];
175222

176223
boolean primitiveBoolean;
224+
boolean primitiveBooleanArray[];
177225
Boolean boxedBoolean;
226+
Boolean boxedBooleanArray[];
178227

179228
float primitiveFloat;
229+
float primitiveFloatArray[];
180230
Float boxedFloat;
231+
Float boxedFloatArray[];
181232

182233
double primitiveDouble;
234+
double primitiveDoubleArray[];
183235
Double boxedDouble;
236+
Double boxedDoubleArray[];
184237

185238
long primitiveLong;
239+
long primitiveLongArray[];
186240
Long boxedLong;
241+
Long boxedLongArray[];
187242

188-
public int getPrimitiveInteger() {
189-
return primitiveInteger;
190-
}
191-
192-
public void setPrimitiveInteger(int primitiveInteger) {
193-
this.primitiveInteger = primitiveInteger;
194-
}
195-
196-
public Integer getBoxedInteger() {
197-
return boxedInteger;
198-
}
199-
200-
public void setBoxedInteger(Integer boxedInteger) {
201-
this.boxedInteger = boxedInteger;
202-
}
203-
204-
public short getPrimitiveShort() {
205-
return primitiveShort;
206-
}
207-
208-
public void setPrimitiveShort(short primitiveShort) {
209-
this.primitiveShort = primitiveShort;
210-
}
211-
212-
public Short getBoxedShort() {
213-
return boxedShort;
214-
}
215-
216-
public void setBoxedShort(Short boxedShort) {
217-
this.boxedShort = boxedShort;
218-
}
219-
220-
public byte getPrimitiveByte() {
221-
return primitiveByte;
222-
}
223-
224-
public void setPrimitiveByte(byte primitiveByte) {
225-
this.primitiveByte = primitiveByte;
226-
}
227-
228-
public Byte getBoxedByte() {
229-
return boxedByte;
230-
}
231-
232-
public void setBoxedByte(Byte boxedByte) {
233-
this.boxedByte = boxedByte;
234-
}
235-
236-
public char getPrimitiveChar() {
237-
return primitiveChar;
238-
}
239-
240-
public void setPrimitiveChar(char primitiveChar) {
241-
this.primitiveChar = primitiveChar;
242-
}
243-
244-
public Character getBoxedChar() {
245-
return boxedChar;
246-
}
247-
248-
public void setBoxedChar(Character boxedChar) {
249-
this.boxedChar = boxedChar;
250-
}
251-
252-
public boolean isPrimitiveBoolean() {
253-
return primitiveBoolean;
254-
}
255-
256-
public void setPrimitiveBoolean(boolean primitiveBoolean) {
257-
this.primitiveBoolean = primitiveBoolean;
258-
}
259-
260-
public Boolean getBoxedBoolean() {
261-
return boxedBoolean;
262-
}
263-
264-
public void setBoxedBoolean(Boolean boxedBoolean) {
265-
this.boxedBoolean = boxedBoolean;
266-
}
267-
268-
public float getPrimitiveFloat() {
269-
return primitiveFloat;
270-
}
271-
272-
public void setPrimitiveFloat(float primitiveFloat) {
273-
this.primitiveFloat = primitiveFloat;
274-
}
275-
276-
public Float getBoxedFloat() {
277-
return boxedFloat;
278-
}
279-
280-
public void setBoxedFloat(Float boxedFloat) {
281-
this.boxedFloat = boxedFloat;
282-
}
283-
284-
public double getPrimitiveDouble() {
285-
return primitiveDouble;
286-
}
287-
288-
public void setPrimitiveDouble(double primitiveDouble) {
289-
this.primitiveDouble = primitiveDouble;
290-
}
291-
292-
public Double getBoxedDouble() {
293-
return boxedDouble;
294-
}
295-
296-
public void setBoxedDouble(Double boxedDouble) {
297-
this.boxedDouble = boxedDouble;
298-
}
299-
300-
public long getPrimitiveLong() {
301-
return primitiveLong;
302-
}
303-
304-
public void setPrimitiveLong(long primitiveLong) {
305-
this.primitiveLong = primitiveLong;
306-
}
307-
308-
public Long getBoxedLong() {
309-
return boxedLong;
310-
}
311-
312-
public void setBoxedLong(Long boxedLong) {
313-
this.boxedLong = boxedLong;
314-
}
243+
String string;
244+
String stringArray[];
315245
}
316246

317247
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.springframework.data.mapping.PersistentPropertyAccessor;
3636
import org.springframework.data.mapping.context.SampleMappingContext;
3737
import org.springframework.data.mapping.context.SamplePersistentProperty;
38+
import org.springframework.data.mapping.model.subpackage.TypeInOtherPackage;
3839

3940
/**
4041
* Unit tests for {@link ClassGeneratingPropertyAccessorFactory}
@@ -76,6 +77,8 @@ public static List<Object[]> parameters() {
7677
ClassGeneratingPropertyAccessorPackageDefaultType.class));
7778
parameters.addAll(parameters(new ClassGeneratingPropertyAccessorPublicType(), propertyNames,
7879
ClassGeneratingPropertyAccessorPublicType.class));
80+
parameters.addAll(parameters(new SubtypeOfTypeInOtherPackage(), propertyNames,
81+
SubtypeOfTypeInOtherPackage.class));
7982

8083
return parameters;
8184
}
@@ -415,6 +418,10 @@ public void setSyntheticProperty(String syntheticProperty) {
415418
}
416419
}
417420

421+
public static class SubtypeOfTypeInOtherPackage extends TypeInOtherPackage{
422+
423+
}
424+
418425
/**
419426
* @see DATACMNS-809
420427
*/

0 commit comments

Comments
 (0)