Skip to content

Commit 2fa2c8f

Browse files
committed
Fix custom validation
1 parent 02a4624 commit 2fa2c8f

File tree

3 files changed

+38
-23
lines changed

3 files changed

+38
-23
lines changed

src/main/java/com/github/rschmitt/dynamicobject/internal/DynamicObjectInstance.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,6 @@ public Object getValueFor(Object key, Type genericReturnType) {
143143
return Conversions.clojureToJava(val, genericReturnType);
144144
}
145145

146-
public D validate(D self) {
147-
Validation.validateInstance(this);
148-
return self;
149-
}
150-
151146
public Object $$noop() {
152147
return this;
153148
}

src/main/java/com/github/rschmitt/dynamicobject/internal/InvokeDynamicInvocationHandler.java

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,12 @@
99
import java.lang.invoke.MethodType;
1010
import java.lang.reflect.Method;
1111
import java.lang.reflect.Type;
12-
import java.util.concurrent.ConcurrentHashMap;
13-
import java.util.concurrent.ConcurrentMap;
1412

1513
import com.github.rschmitt.dynamicobject.DynamicObject;
14+
1615
import net.fushizen.invokedynamic.proxy.DynamicInvocationHandler;
1716

1817
public class InvokeDynamicInvocationHandler implements DynamicInvocationHandler {
19-
private static final ConcurrentMap<Class, MethodHandle> validateMethodHandleCache = new ConcurrentHashMap<>();
20-
2118
private final Class dynamicObjectType;
2219

2320
public InvokeDynamicInvocationHandler(Class dynamicObjectType) {
@@ -34,22 +31,19 @@ public CallSite handleInvocation(
3431
) throws Throwable {
3532
Class proxyType = methodType.parameterArray()[0];
3633
MethodHandle mh;
37-
if (superMethod != null) {
34+
if (superMethod != null && !"validate".equals(methodName)) {
3835
mh = superMethod.asType(methodType);
39-
if ("validate".equals(methodName)) {
40-
if (mh.type().returnType().equals(dynamicObjectType))
41-
return new ConstantCallSite(mh);
42-
else
43-
validateMethodHandleCache.put(dynamicObjectType, mh);
44-
} else return new ConstantCallSite(mh);
36+
return new ConstantCallSite(mh);
4537
}
4638
if ("validate".equals(methodName)) {
47-
mh = lookup.findSpecial(DynamicObjectInstance.class, "$$validate", methodType(Object.class, new Class[]{ }), proxyType).asType(methodType);
39+
mh = lookup.findSpecial(DynamicObjectInstance.class, "$$validate", methodType(Object.class, new Class[]{}), proxyType).asType(methodType);
4840
} else if ("$$customValidate".equals(methodName)) {
49-
mh = validateMethodHandleCache.getOrDefault(
50-
dynamicObjectType,
51-
lookup.findSpecial(DynamicObjectInstance.class, "$$noop", methodType(Object.class), proxyType).asType(methodType)
52-
);
41+
try {
42+
mh = lookup.findSpecial(dynamicObjectType, "validate", methodType(dynamicObjectType), proxyType);
43+
} catch (NoSuchMethodException ex) {
44+
mh = lookup.findSpecial(DynamicObjectInstance.class, "$$noop", methodType(Object.class, new Class[]{}), proxyType);
45+
}
46+
mh = mh.asType(methodType);
5347
} else {
5448
Method method = dynamicObjectType.getMethod(methodName, methodType.dropParameterTypes(0, 1).parameterArray());
5549

src/test/java/com/github/rschmitt/dynamicobject/ValidationTest.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,29 @@ public void nullRequiredFieldThrowsException() {
169169
instance.x();
170170
}
171171

172-
@Test
172+
@Test(expected = IllegalStateException.class)
173173
public void customValidation() {
174174
validationSuccess("{:oddsOnly 5, :required 0}", Custom.class);
175+
DynamicObject.deserialize("{:oddsOnly 4, :required 0}", Custom.class).validate();
175176
validationFailure("{:oddsOnly 4, :required 0}", Custom.class);
176177
validationFailure("{:oddsOnly 5}", Custom.class);
177178
}
178179

180+
@Test(expected = IllegalStateException.class)
181+
public void customValidationRunsLast() {
182+
newInstance(Custom2.class).validate();
183+
}
184+
185+
@Test(expected = CustomException.class)
186+
public void customExceptionsArePropagated() {
187+
newInstance(Custom2.class).str("value").validate();
188+
}
189+
190+
@Test(expected = CustomException.class)
191+
public void customExceptionsArePropagated2() {
192+
DynamicObject.deserialize("{:str \"value\"}", Custom2.class).validate();
193+
}
194+
179195
private static <D extends DynamicObject<D>> void validationFailure(String edn, Class<D> type) {
180196
try {
181197
deserialize(edn, type).validate();
@@ -254,11 +270,21 @@ public interface Custom extends DynamicObject<Custom> {
254270
@Required int oddsOnly();
255271
@Required int required();
256272

257-
@Override
258273
default Custom validate() {
259274
if (oddsOnly() % 2 == 0)
260275
throw new IllegalStateException("Odd number expected");
261276
return this;
262277
}
263278
}
279+
280+
public interface Custom2 extends DynamicObject<Custom2> {
281+
@Required String str();
282+
Custom2 str(String str);
283+
284+
default Custom2 validate() {
285+
throw new CustomException();
286+
}
287+
}
288+
289+
public static class CustomException extends RuntimeException {}
264290
}

0 commit comments

Comments
 (0)