diff --git a/pom.xml b/pom.xml
index 555b44b..7be0cc1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
4.0.0
net.helenus
helenus-core
- 2.0.17-SNAPSHOT
+ 2.0.19-SNAPSHOT
jar
helenus
diff --git a/src/main/java/net/helenus/core/reflect/MapperInvocationHandler.java b/src/main/java/net/helenus/core/reflect/MapperInvocationHandler.java
index c1e55bd..08656b5 100644
--- a/src/main/java/net/helenus/core/reflect/MapperInvocationHandler.java
+++ b/src/main/java/net/helenus/core/reflect/MapperInvocationHandler.java
@@ -15,6 +15,7 @@
*/
package net.helenus.core.reflect;
+import java.io.Serializable;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
@@ -24,9 +25,11 @@ import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.Map;
+import net.helenus.mapping.annotation.Transient;
import net.helenus.support.HelenusException;
-public class MapperInvocationHandler implements InvocationHandler {
+public class MapperInvocationHandler implements InvocationHandler, Serializable {
+ private static final long serialVersionUID = -7044209982830584984L;
private final Map src;
private final Class iface;
@@ -36,25 +39,31 @@ public class MapperInvocationHandler implements InvocationHandler {
this.iface = iface;
}
+ private Object invokeDefault(Object proxy, Method method, Object[] args) throws Throwable {
+ // NOTE: This is reflection magic to invoke (non-recursively) a default method implemented on an interface
+ // that we've proxied (in ReflectionDslInstantiator). I found the answer in this article.
+ // https://zeroturnaround.com/rebellabs/recognize-and-conquer-java-proxies-default-methods-and-method-handles/
+
+ // First, we need an instance of a private inner-class found in MethodHandles.
+ Constructor constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class,
+ int.class);
+ constructor.setAccessible(true);
+
+ // Now we need to lookup and invoke special the default method on the interface class.
+ final Class> declaringClass = method.getDeclaringClass();
+ Object result = constructor.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
+ .unreflectSpecial(method, declaringClass)
+ .bindTo(proxy)
+ .invokeWithArguments(args);
+ return result;
+ }
+
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if (method.isDefault()) {
- // NOTE: This is reflection magic to invoke (non-recursively) a default method implemented on an interface
- // that we've proxied (in ReflectionDslInstantiator). I found the answer in this article.
- // https://zeroturnaround.com/rebellabs/recognize-and-conquer-java-proxies-default-methods-and-method-handles/
-
- // First, we need an instance of a private inner-class found in MethodHandles.
- Constructor constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
- constructor.setAccessible(true);
-
- // Now we need to lookup and invoke special the default method on the interface class.
- final Class> declaringClass = method.getDeclaringClass();
- Object result = constructor.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
- .unreflectSpecial(method, declaringClass)
- .bindTo(proxy)
- .invokeWithArguments(args);
- return result;
+ // Transient, default methods should simply be invoked as-is.
+ if (method.isDefault() && method.getDeclaredAnnotation(Transient.class) != null) {
+ return invokeDefault(proxy, method, args);
}
String methodName = method.getName();
@@ -92,15 +101,20 @@ public class MapperInvocationHandler implements InvocationHandler {
if (value == null) {
- if (returnType.isPrimitive()) {
+ // Default implementations of non-Transient methods in entities are the default value when the
+ // map contains 'null'.
+ if (method.isDefault()) {
+ return invokeDefault(proxy, method, args);
+ }
+ // Otherwise, if the return type of the method is a primitive Java type then we'll return the standard
+ // default values to avoid a NPE in user code.
+ if (returnType.isPrimitive()) {
DefaultPrimitiveTypes type = DefaultPrimitiveTypes.lookup(returnType);
if (type == null) {
throw new HelenusException("unknown primitive type " + returnType);
}
-
return type.getDefaultValue();
-
}
}