diff --git a/src/main/java/org/springframework/data/mapping/PersistentProperty.java b/src/main/java/org/springframework/data/mapping/PersistentProperty.java index b975228ac..d23a515d6 100644 --- a/src/main/java/org/springframework/data/mapping/PersistentProperty.java +++ b/src/main/java/org/springframework/data/mapping/PersistentProperty.java @@ -114,10 +114,27 @@ public interface PersistentProperty
> { } /** - * Returns the wither method to set a property value on a new object instance. Might return {@literal null} in case - * there is no wither available. + * Returns the wither {@link Method} to set a property value on a new object instance. Might return {@literal null} in + * case there is no wither available. + *
+ * Wither {@link Method methods} are property-bound instance {@link Method methods} that accept a single argument of + * the property type creating a new object instance. * - * @return the wither method to set a property value on a new object instance if available, otherwise {@literal null}. + *
+ * class Person {
+ * final String id;
+ * final String name;
+ *
+ * // …
+ *
+ * Person withName(String name) {
+ * return new Person(this.id, name);
+ * }
+ * }
+ *
+ *
+ * @return the wither {@link Method} to set a property value on a new object instance if available, otherwise
+ * {@literal null}.
* @since 2.1
*/
@Nullable
@@ -247,6 +264,7 @@ public interface PersistentProperty> { * {@code final}. * * @return + * @see java.lang.reflect.Modifier#isFinal(int) * @since 2.1 */ boolean isImmutable(); @@ -366,7 +384,7 @@ public interface PersistentProperty
> {
/**
* Return the type the property refers to in case it's an association.
- *
+ *
* @return the type the property refers to in case it's an association or {@literal null} in case it's not an
* association, the target entity type is not explicitly defined (either explicitly or through the property
* type itself).
diff --git a/src/main/java/org/springframework/data/mapping/PersistentPropertyAccessor.java b/src/main/java/org/springframework/data/mapping/PersistentPropertyAccessor.java
index 42e5e88e7..f8569df5e 100644
--- a/src/main/java/org/springframework/data/mapping/PersistentPropertyAccessor.java
+++ b/src/main/java/org/springframework/data/mapping/PersistentPropertyAccessor.java
@@ -123,7 +123,8 @@ public interface PersistentPropertyAccessor {
}
/**
- * Returns the underlying bean. May change between {@link #setProperty(PersistentProperty, Object)} calls.
+ * Returns the underlying bean. The actual instance may change between
+ * {@link #setProperty(PersistentProperty, Object)} calls.
*
* @return will never be {@literal null}.
*/
diff --git a/src/main/java/org/springframework/data/mapping/model/BeanWrapper.java b/src/main/java/org/springframework/data/mapping/model/BeanWrapper.java
index f0ec9f20b..ee352c15a 100644
--- a/src/main/java/org/springframework/data/mapping/model/BeanWrapper.java
+++ b/src/main/java/org/springframework/data/mapping/model/BeanWrapper.java
@@ -160,37 +160,62 @@ class BeanWrapper
- * {
- * @code
- * public class PersonWithId_Accessor_zd4wnl implements PersistentPropertyAccessor {
- * private final Object bean;
- * private static final MethodHandle $id_fieldGetter;
- * private static final MethodHandle $id_fieldSetter;
+ *
+ * public class PersonWithId_Accessor_zd4wnl implements PersistentPropertyAccessor {
+ * private final Object bean;
+ * private static final MethodHandle $id_fieldGetter;
+ * private static final MethodHandle $id_fieldSetter;
+ *
+ * // ...
+ * public PersonWithId_Accessor_zd4wnl(Object bean) {
+ * this.bean = bean;
+ * }
+ *
+ * static {
+ * Method getter;
+ * Method setter;
+ * MethodHandles.Lookup lookup = MethodHandles.lookup();
+ * Class class_1 = Class.forName("org.springframework.data.mapping.Person");
+ * Class class_2 = Class.forName("org.springframework.data.mapping.PersonWithId");
+ * Field field = class_2.getDeclaredField("id");
+ * field.setAccessible(true);
+ * $id_fieldGetter = lookup.unreflectGetter(field);
+ * $id_fieldSetter = lookup.unreflectSetter(field);
* // ...
- * public PersonWithId_Accessor_zd4wnl(Object bean) {
- * this.bean = bean;
- * }
- * static {
- * Method getter;
- * Method setter;
- * MethodHandles.Lookup lookup = MethodHandles.lookup();
- * Class class_1 = Class.forName("org.springframework.data.mapping.Person");
- * Class class_2 = Class.forName("org.springframework.data.mapping.PersonWithId");
- * Field field = class_2.getDeclaredField("id");
- * field.setAccessible(true);
- * $id_fieldGetter = lookup.unreflectGetter(field);
- * $id_fieldSetter = lookup.unreflectSetter(field);
- * // ...
- * }
- * public Object getBean() {
- * return this.bean;
- * }
- * public void setProperty(PersistentProperty> property, Object value) {
- * Object bean = this.bean;
- * switch (property.getName().hashCode()) {
- * case 3355:
- * $id_fieldSetter.invoke(bean, value);
- * return;
- * case 3357:
- * this.bean = $id_wither.invoke(bean, value);
- * case 3358:
- * this.bean = bean.withId(value);
- * return;
- * case 3359:
- * this.bean = bean.copy(value); // Kotlin
- * case 3360:
- * this.bean = PersonWithId.copy$default(bean, value, 0, null); // Kotlin
- * // ...
- * }
- * throw new UnsupportedOperationException(
- * String.format("No accessor to set property %s!", new Object[] { property }));
- * }
- * public Object getProperty(PersistentProperty> property){
- * Object bean = this.bean;
- * switch (property.getName().hashCode()) {
- * case 3355:
- * return id_fieldGetter..invoke(bean);
- * case 3356:
- * return bean.getField();
- * // ...
- * case 3357:
- * return bean.field;
- * // ...
- * throw new UnsupportedOperationException(
- * String.format("No accessor to get property %s!", new Object[] { property }));
- * }
+ * }
+ *
+ * public Object getBean() {
+ * return this.bean;
+ * }
+ *
+ * public void setProperty(PersistentProperty> property, Object value) {
+ * Object bean = this.bean;
+ * switch (property.getName().hashCode()) {
+ * case 3355:
+ * $id_fieldSetter.invoke(bean, value);
+ * return;
+ * case 3357:
+ * this.bean = $id_wither.invoke(bean, value);
+ * return;
+ * case 3358:
+ * this.bean = bean.withId(value);
+ * return;
+ * case 3359:
+ * this.bean = PersonWithId.copy$default(bean, value, 0, null); // Kotlin
+ * return;
+ * // …
+ * }
+ * throw new UnsupportedOperationException(
+ * String.format("No accessor to set property %s!", new Object[] { property }));
+ * }
+ *
+ * public Object getProperty(PersistentProperty> property) {
+ * Object bean = this.bean;
+ * switch (property.getName().hashCode()) {
+ * case 3355:
+ * return id_fieldGetter.invoke(bean);
+ * case 3356:
+ * return bean.getField();
+ * // …
+ * case 3357:
+ * return bean.field;
+ * // …
+ * throw new UnsupportedOperationException(
+ * String.format("No accessor to get property %s!", new Object[] { property }));
+ * }
+ * }
* }
*
*
@@ -368,14 +373,11 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
/**
* Generates field declarations for private-visibility properties.
*
- *
- * {
- * @code
- * private final Object bean;
- * private static final MethodHandle $id_fieldGetter;
- * private static final MethodHandle $id_fieldSetter;
- * // ...
- * }
+ *
+ * private final Object bean;
+ * private static final MethodHandle $id_fieldGetter;
+ * private static final MethodHandle $id_fieldSetter;
+ * // …
*
*/
private static void visitFields(PersistentEntity, ?> entity, List
- * {
- * @code
- * public PersonWithId_Accessor_zd4wnl(PersonWithId bean) {
- * this.bean = bean;
- * }
+ *
+ * public PersonWithId_Accessor_zd4wnl(PersonWithId bean) {
+ * this.bean = bean;
* }
*
*/
@@ -447,8 +446,8 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
// Assert.notNull(bean)
mv.visitVarInsn(ALOAD, 1);
mv.visitLdcInsn("Bean must not be null!");
- mv.visitMethodInsn(INVOKESTATIC, "org/springframework/util/Assert", "notNull", String.format("(%s%s)V",
- BytecodeUtil.referenceName(JAVA_LANG_OBJECT), BytecodeUtil.referenceName(JAVA_LANG_STRING)), false);
+ mv.visitMethodInsn(INVOKESTATIC, "org/springframework/util/Assert", "notNull",
+ String.format("(%s%s)V", referenceName(JAVA_LANG_OBJECT), referenceName(JAVA_LANG_STRING)), false);
// this.bean = bean
mv.visitVarInsn(ALOAD, 0);
@@ -459,7 +458,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
mv.visitInsn(RETURN);
Label l3 = new Label();
mv.visitLabel(l3);
- mv.visitLocalVariable(THIS_REF, BytecodeUtil.referenceName(internalClassName), null, l0, l3, 0);
+ mv.visitLocalVariable(THIS_REF, referenceName(internalClassName), null, l0, l3, 0);
mv.visitLocalVariable(BEAN_FIELD, getAccessibleTypeReferenceName(entity), null, l0, l3, 1);
mv.visitMaxs(2, 2);
@@ -468,20 +467,19 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
/**
* Generates the static initializer block.
*
- *
- * @code
- * static {
- * Method getter;
- * Method setter;
- * MethodHandles.Lookup lookup = MethodHandles.lookup();
- * Class class_1 = Class.forName("org.springframework.data.mapping.Person");
- * Class class_2 = Class.forName("org.springframework.data.mapping.PersonWithId");
- * Field field = class_2.getDeclaredField("id");
- * field.setAccessible(true);
- * $id_fieldGetter = lookup.unreflectGetter(field);
- * $id_fieldSetter = lookup.unreflectSetter(field);
- * // ...
- * }
+ *
+ * static {
+ * Method getter;
+ * Method setter;
+ * MethodHandles.Lookup lookup = MethodHandles.lookup();
+ * Class class_1 = Class.forName("org.springframework.data.mapping.Person");
+ * Class class_2 = Class.forName("org.springframework.data.mapping.PersonWithId");
+ * Field field = class_2.getDeclaredField("id");
+ * field.setAccessible(true);
+ * $id_fieldGetter = lookup.unreflectGetter(field);
+ * $id_fieldSetter = lookup.unreflectSetter(field);
+ * // …
+ * }
*
*/
private static void visitStaticInitializer(PersistentEntity, ?> entity,
@@ -495,7 +493,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
// lookup = MethodHandles.lookup()
mv.visitMethodInsn(INVOKESTATIC, JAVA_LANG_INVOKE_METHOD_HANDLES, "lookup",
- String.format("()%s", BytecodeUtil.referenceName(JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP)), false);
+ String.format("()%s", referenceName(JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP)), false);
mv.visitVarInsn(ASTORE, 0);
List
- * {
- * @code
- * public Optional extends Object> getProperty(PersistentProperty> property){
- * Object bean = this.bean;
- * switch (property.getName().hashCode()) {
- * case 3355:
- * return id_fieldGetter..invoke(bean);
- * case 3356:
- * return bean.getField();
- * // ...
- * case 3357:
- * return bean.field;
- * // ...
- * }
- * throw new UnsupportedOperationException(
- * String.format("No MethodHandle to get property %s", new Object[] { property }));
- * }
+ *
+ * public Object getProperty(PersistentProperty> property) {
+ * Object bean = this.bean;
+ * switch (property.getName().hashCode()) {
+ * case 3355:
+ * return id_fieldGetter.invoke(bean);
+ * case 3356:
+ * return bean.getField();
+ * // …
+ * case 3357:
+ * return bean.field;
+ * // …
+ * }
+ * throw new UnsupportedOperationException(
+ * String.format("No MethodHandle to get property %s", new Object[] { property }));
* }
*
*/
@@ -800,8 +777,8 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
mv.visitLabel(l1);
visitThrowUnsupportedOperationException(mv, "No accessor to get property %s!");
- mv.visitLocalVariable(THIS_REF, BytecodeUtil.referenceName(internalClassName), null, l0, l1, 0);
- mv.visitLocalVariable("property", BytecodeUtil.referenceName(PERSISTENT_PROPERTY),
+ mv.visitLocalVariable(THIS_REF, referenceName(internalClassName), null, l0, l1, 0);
+ mv.visitLocalVariable("property", referenceName(PERSISTENT_PROPERTY),
"Lorg/springframework/data/mapping/PersistentProperty<*>;", l0, l1, 1);
mv.visitLocalVariable(BEAN_FIELD, getAccessibleTypeReferenceName(entity), null, l0, l1, 2);
@@ -834,7 +811,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEINTERFACE, PERSISTENT_PROPERTY, "getName",
- String.format("()%s", BytecodeUtil.referenceName(JAVA_LANG_STRING)), true);
+ String.format("()%s", referenceName(JAVA_LANG_STRING)), true);
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_STRING, "hashCode", "()I", false);
mv.visitLookupSwitchInsn(dfltLabel, hashes, switchJumpLabels);
@@ -868,12 +845,12 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
if (generateMethodHandle(entity, getter)) {
// $getter.invoke(bean)
mv.visitFieldInsn(GETSTATIC, internalClassName, getterName(property),
- BytecodeUtil.referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
+ referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
mv.visitVarInsn(ALOAD, 2);
- mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLE, "invoke", String.format("(%s)%s",
- BytecodeUtil.referenceName(JAVA_LANG_OBJECT), BytecodeUtil.referenceName(JAVA_LANG_OBJECT)), false);
+ mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLE, "invoke",
+ String.format("(%s)%s", referenceName(JAVA_LANG_OBJECT), referenceName(JAVA_LANG_OBJECT)), false);
} else {
- // bean.get...
+ // bean.get…
mv.visitVarInsn(ALOAD, 2);
int invokeOpCode = INVOKEVIRTUAL;
@@ -885,8 +862,8 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
}
mv.visitMethodInsn(invokeOpCode, Type.getInternalName(declaringClass), getter.getName(),
- String.format("()%s", BytecodeUtil.signatureTypeName(getter.getReturnType())), interfaceDefinition);
- BytecodeUtil.autoboxIfNeeded(getter.getReturnType(), BytecodeUtil.autoboxType(getter.getReturnType()), mv);
+ String.format("()%s", signatureTypeName(getter.getReturnType())), interfaceDefinition);
+ autoboxIfNeeded(getter.getReturnType(), autoboxType(getter.getReturnType()), mv);
}
} else {
@@ -895,16 +872,16 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
if (generateMethodHandle(entity, field)) {
// $fieldGetter.invoke(bean)
mv.visitFieldInsn(GETSTATIC, internalClassName, fieldGetterName(property),
- BytecodeUtil.referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
+ referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
mv.visitVarInsn(ALOAD, 2);
- mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLE, "invoke", String.format("(%s)%s",
- BytecodeUtil.referenceName(JAVA_LANG_OBJECT), BytecodeUtil.referenceName(JAVA_LANG_OBJECT)), false);
+ mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLE, "invoke",
+ String.format("(%s)%s", referenceName(JAVA_LANG_OBJECT), referenceName(JAVA_LANG_OBJECT)), false);
} else {
// bean.field
mv.visitVarInsn(ALOAD, 2);
mv.visitFieldInsn(GETFIELD, Type.getInternalName(field.getDeclaringClass()), field.getName(),
- BytecodeUtil.signatureTypeName(field.getType()));
- BytecodeUtil.autoboxIfNeeded(field.getType(), BytecodeUtil.autoboxType(field.getType()), mv);
+ signatureTypeName(field.getType()));
+ autoboxIfNeeded(field.getType(), autoboxType(field.getType()), mv);
}
}
@@ -914,29 +891,27 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
/**
* Generate the {@link PersistentPropertyAccessor#setProperty(PersistentProperty, Object)} method.
*
- *
- * {
- * @code
- * public void setProperty(PersistentProperty> property, Optional extends Object> value) {
- * Object bean = this.bean;
- * switch (property.getName().hashCode()) {
- * case 3355:
- * $id_fieldSetter.invoke(bean, value);
- * return;
- * case 3357:
- * this.bean = $id_fieldWither.invoke(bean, value);
- * case 3358:
- * this.bean = bean.withId(value);
- * case 3359:
- * this.bean = bean.copy(value); // Kotlin
- * case 3360:
- * this.bean = PersonWithId.copy$default(bean, value, 0, null); // Kotlin
- * // ...
- * }
- * throw new UnsupportedOperationException(
- * String.format("No accessor to set property %s!", new Object[] { property }));
- * }
- * }
+ *
+ * public void setProperty(PersistentProperty> property, Optional extends Object> value) {
+ * Object bean = this.bean;
+ * switch (property.getName().hashCode()) {
+ * case 3355:
+ * $id_fieldSetter.invoke(bean, value);
+ * return;
+ * case 3357:
+ * this.bean = $id_fieldWither.invoke(bean, value);
+ * return;
+ * case 3358:
+ * this.bean = bean.withId(value);
+ * return;
+ * case 3359:
+ * this.bean = PersonWithId.copy$default(bean, value, 0, null); // Kotlin
+ * return;
+ * // …
+ * }
+ * throw new UnsupportedOperationException(
+ * String.format("No accessor to set property %s!", new Object[] { property }));
+ * }
*
*/
private static void visitSetProperty(PersistentEntity, ?> entity,
@@ -965,10 +940,10 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
visitThrowUnsupportedOperationException(mv, "No accessor to set property %s!");
- mv.visitLocalVariable(THIS_REF, BytecodeUtil.referenceName(internalClassName), null, l0, l1, 0);
+ mv.visitLocalVariable(THIS_REF, referenceName(internalClassName), null, l0, l1, 0);
mv.visitLocalVariable("property", "Lorg/springframework/data/mapping/PersistentProperty;",
"Lorg/springframework/data/mapping/PersistentProperty<*>;", l0, l1, 1);
- mv.visitLocalVariable("value", BytecodeUtil.referenceName(JAVA_LANG_OBJECT), null, l0, l1, 2);
+ mv.visitLocalVariable("value", referenceName(JAVA_LANG_OBJECT), null, l0, l1, 2);
mv.visitLocalVariable(BEAN_FIELD, getAccessibleTypeReferenceName(entity), null, l0, l1, 3);
@@ -999,7 +974,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEINTERFACE, PERSISTENT_PROPERTY, "getName",
- String.format("()%s", BytecodeUtil.referenceName(JAVA_LANG_STRING)), true);
+ String.format("()%s", referenceName(JAVA_LANG_STRING)), true);
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_STRING, "hashCode", "()I", false);
mv.visitLookupSwitchInsn(dfltLabel, hashes, switchJumpLabels);
@@ -1032,147 +1007,213 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
if (property.isImmutable()) {
if (wither != null) {
- if (generateMethodHandle(entity, wither)) {
-
- // this. <- for later PUTFIELD
- mv.visitVarInsn(ALOAD, 0);
-
- // $wither.invoke(bean)
- mv.visitFieldInsn(GETSTATIC, internalClassName, witherName(property),
- BytecodeUtil.referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
- mv.visitVarInsn(ALOAD, 3);
- mv.visitVarInsn(ALOAD, 2);
- mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLE, "invoke",
- String.format("(%s%s)%s", BytecodeUtil.referenceName(JAVA_LANG_OBJECT),
- BytecodeUtil.referenceName(JAVA_LANG_OBJECT), getAccessibleTypeReferenceName(entity)),
- false);
-
- mv.visitTypeInsn(CHECKCAST, getAccessibleTypeReferenceName(entity));
- } else {
-
- // this. <- for later PUTFIELD
- mv.visitVarInsn(ALOAD, 0);
-
- // bean.set...(object)
- mv.visitVarInsn(ALOAD, 3);
- mv.visitVarInsn(ALOAD, 2);
-
- visitInvokeMethodSingleArg(mv, wither);
- }
-
- mv.visitFieldInsn(PUTFIELD, internalClassName, BEAN_FIELD, getAccessibleTypeReferenceName(entity));
+ visitWithProperty(entity, property, mv, internalClassName, wither);
}
if (hasKotlinCopyMethod(entity.getType())) {
-
- // this. <- for later PUTFIELD
- mv.visitVarInsn(ALOAD, 0);
-
- Optional
+ * this.bean = this.bean = bean.withId(value);
+ *
+ */
+ private static void visitWithProperty(PersistentEntity, ?> entity, PersistentProperty> property,
+ MethodVisitor mv, String internalClassName, Method wither) {
+
+ if (generateMethodHandle(entity, wither)) {
+
+ // this. <- for later PUTFIELD
+ mv.visitVarInsn(ALOAD, 0);
+
+ // $wither.invoke(bean)
+ mv.visitFieldInsn(GETSTATIC, internalClassName, witherName(property),
+ referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitVarInsn(ALOAD, 2);
+ mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLE, "invoke", String.format("(%s%s)%s",
+ referenceName(JAVA_LANG_OBJECT), referenceName(JAVA_LANG_OBJECT), getAccessibleTypeReferenceName(entity)),
+ false);
+
+ mv.visitTypeInsn(CHECKCAST, getAccessibleTypeReferenceName(entity));
+ } else {
+
+ // this. <- for later PUTFIELD
+ mv.visitVarInsn(ALOAD, 0);
+
+ // bean.set...(object)
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitVarInsn(ALOAD, 2);
+
+ visitInvokeMethodSingleArg(mv, wither);
+ }
+
+ mv.visitFieldInsn(PUTFIELD, internalClassName, BEAN_FIELD, getAccessibleTypeReferenceName(entity));
+ }
+
+ /**
+ * Generates:
+ *
+ *
+ * this.bean = bean.copy(value);
+ *
+ *
+ * or
+ *
+ *
+ * this.bean = bean.copy$default..(bean, object, MASK, null)
+ *
+ */
+ private static void visitKotlinCopy(PersistentEntity, ?> entity, PersistentProperty> property, MethodVisitor mv,
+ String internalClassName) {
+
+ // this. <- for later PUTFIELD
+ mv.visitVarInsn(ALOAD, 0);
+
+ Optional
+ * $id_fieldSetter.invoke(bean, value);
+ *
+ *
+ * or
+ *
+ *
+ * bean.setId(value);
+ *
+ */
+ private static void visitSetProperty(PersistentEntity, ?> entity, PersistentProperty> property,
+ MethodVisitor mv, String internalClassName, Method setter) {
+
+ if (generateMethodHandle(entity, setter)) {
+
+ // $setter.invoke(bean)
+ mv.visitFieldInsn(GETSTATIC, internalClassName, setterName(property),
+ referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitVarInsn(ALOAD, 2);
+ mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLE, "invoke",
+ String.format("(%s%s)V", referenceName(JAVA_LANG_OBJECT), referenceName(JAVA_LANG_OBJECT)), false);
+ } else {
+
+ // bean.set...(object)
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitVarInsn(ALOAD, 2);
+
+ visitInvokeMethodSingleArg(mv, setter);
+ }
+ }
+
+ /**
+ * Generate:
+ *
+ *
+ * $id_fieldSetter.invoke(bean, value);
+ *
+ *
+ * or
+ *
+ *
+ * bean.id = value;
+ *
+ */
+ private static void visitSetField(PersistentEntity, ?> entity, PersistentProperty> property, MethodVisitor mv,
+ String internalClassName) {
+
+ Field field = property.getField();
+ if (field != null) {
+ if (generateSetterMethodHandle(entity, field)) {
+ // $fieldSetter.invoke(bean, object)
+ mv.visitFieldInsn(GETSTATIC, internalClassName, fieldSetterName(property),
+ referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitVarInsn(ALOAD, 2);
+ mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLE, "invoke",
+ String.format("(%s%s)V", referenceName(JAVA_LANG_OBJECT), referenceName(JAVA_LANG_OBJECT)), false);
+ } else {
+ // bean.field
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitVarInsn(ALOAD, 2);
+
+ Class> fieldType = field.getType();
+
+ mv.visitTypeInsn(CHECKCAST, Type.getInternalName(autoboxType(fieldType)));
+ autoboxIfNeeded(autoboxType(fieldType), fieldType, mv);
+ mv.visitFieldInsn(PUTFIELD, Type.getInternalName(field.getDeclaringClass()), field.getName(),
+ signatureTypeName(fieldType));
+ }
+ }
+ }
+
/**
* Creates the method signature containing parameter types (e.g. (Ljava/lang/Object)I for a method accepting
* {@link Object} and returning a primitive {@code int}).
*
* @param method
* @return
+ * @since 2.1
*/
private static String getArgumentSignature(Method method) {
@@ -1182,49 +1223,22 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
for (Class> parameterType : method.getParameterTypes()) {
result.append("%s");
- argumentTypes.add(BytecodeUtil.signatureTypeName(parameterType));
+ argumentTypes.add(signatureTypeName(parameterType));
}
result.append(")%s");
- argumentTypes.add(BytecodeUtil.signatureTypeName(method.getReturnType()));
+ argumentTypes.add(signatureTypeName(method.getReturnType()));
return String.format(result.toString(), argumentTypes.toArray());
}
- private static void visitDefaultValue(MethodVisitor mv, Class> parameterType) {
- if (parameterType.isPrimitive()) {
-
- if (parameterType == Integer.TYPE || parameterType == Short.TYPE || parameterType == Boolean.TYPE) {
- mv.visitInsn(Opcodes.ICONST_0);
- }
-
- if (parameterType == Long.TYPE) {
- mv.visitInsn(Opcodes.LCONST_0);
- }
-
- if (parameterType == Double.TYPE) {
- mv.visitInsn(Opcodes.DCONST_0);
- }
-
- if (parameterType == Float.TYPE) {
- mv.visitInsn(Opcodes.FCONST_0);
- }
-
- if (parameterType == Character.TYPE || parameterType == Byte.TYPE) {
- mv.visitIntInsn(Opcodes.BIPUSH, 0);
- }
- } else {
- mv.visitInsn(Opcodes.ACONST_NULL);
- }
- }
-
private static void visitAssertNotNull(MethodVisitor mv) {
// Assert.notNull(property)
mv.visitVarInsn(ALOAD, 1);
mv.visitLdcInsn("Property must not be null!");
- mv.visitMethodInsn(INVOKESTATIC, "org/springframework/util/Assert", "notNull", String.format("(%s%s)V",
- BytecodeUtil.referenceName(JAVA_LANG_OBJECT), BytecodeUtil.referenceName(JAVA_LANG_STRING)), false);
+ mv.visitMethodInsn(INVOKESTATIC, "org/springframework/util/Assert", "notNull",
+ String.format("(%s%s)V", referenceName(JAVA_LANG_OBJECT), referenceName(JAVA_LANG_STRING)), false);
}
private static void visitThrowUnsupportedOperationException(MethodVisitor mv, String message) {
@@ -1273,10 +1287,10 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
private static String getAccessibleTypeReferenceName(PersistentEntity, ?> entity) {
if (isAccessible(entity)) {
- return BytecodeUtil.referenceName(entity.getType());
+ return referenceName(entity.getType());
}
- return BytecodeUtil.referenceName(JAVA_LANG_OBJECT);
+ return referenceName(JAVA_LANG_OBJECT);
}
private static boolean generateSetterMethodHandle(PersistentEntity, ?> entity, @Nullable Field field) {
@@ -1301,8 +1315,10 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
if (isAccessible(entity)) {
- if (Modifier.isProtected(member.getModifiers()) || BytecodeUtil.isDefault(member.getModifiers())) {
- if (!member.getDeclaringClass().getPackage().equals(entity.getType().getPackage())) {
+ if (Modifier.isProtected(member.getModifiers()) || isDefault(member.getModifiers())) {
+ Package declaringPackage = member.getDeclaringClass().getPackage();
+
+ if (declaringPackage != null && !declaringPackage.equals(entity.getType().getPackage())) {
return true;
}
}
@@ -1334,14 +1350,13 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
Class> declaringClass = method.getDeclaringClass();
boolean interfaceDefinition = declaringClass.isInterface();
- mv.visitTypeInsn(CHECKCAST, Type.getInternalName(BytecodeUtil.autoboxType(parameterType)));
- BytecodeUtil.autoboxIfNeeded(BytecodeUtil.autoboxType(parameterType), parameterType, mv);
+ mv.visitTypeInsn(CHECKCAST, Type.getInternalName(autoboxType(parameterType)));
+ autoboxIfNeeded(autoboxType(parameterType), parameterType, mv);
int invokeOpCode = getInvokeOp(method, interfaceDefinition);
- mv.visitMethodInsn(
- invokeOpCode, Type.getInternalName(method.getDeclaringClass()), method.getName(), String.format("(%s)%s",
- BytecodeUtil.signatureTypeName(parameterType), BytecodeUtil.signatureTypeName(method.getReturnType())),
+ mv.visitMethodInsn(invokeOpCode, Type.getInternalName(method.getDeclaringClass()), method.getName(),
+ String.format("(%s)%s", signatureTypeName(parameterType), signatureTypeName(method.getReturnType())),
interfaceDefinition);
}
@@ -1453,7 +1468,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
*/
private static boolean hasKotlinCopyMethod(Class> type) {
- if (BytecodeUtil.isAccessible(type) && org.springframework.data.util.ReflectionUtils.isKotlinClass(type)) {
+ if (isAccessible(type) && org.springframework.data.util.ReflectionUtils.isKotlinClass(type)) {
return findCopyMethod(type) != null;
}
diff --git a/src/main/java/org/springframework/data/mapping/model/Property.java b/src/main/java/org/springframework/data/mapping/model/Property.java
index 926f429f4..34fc4f07e 100644
--- a/src/main/java/org/springframework/data/mapping/model/Property.java
+++ b/src/main/java/org/springframework/data/mapping/model/Property.java
@@ -83,7 +83,8 @@ public class Property {
private static Optional