Skip to content

Commit f45e2be

Browse files
mp911deodrotbohm
authored andcommitted
DATACMNS-1200 - Guard casts to primitive type in ClassGeneratingEntityInstantiator.
We now insert assertions for primitive types before passing these to the actual constructor to prevent NullPointerExceptions. We also output the index/parameter name if the parameter was null. Original pull request: #255.
1 parent d1fc97e commit f45e2be

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

src/main/java/org/springframework/data/convert/ClassGeneratingEntityInstantiator.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.security.PrivilegedAction;
2424
import java.util.Arrays;
2525
import java.util.HashMap;
26+
import java.util.List;
2627
import java.util.Map;
2728

2829
import org.springframework.asm.ClassWriter;
@@ -399,6 +400,7 @@ private void visitCreateMethod(ClassWriter cw, PersistentEntity<?, ?> entity,
399400

400401
Constructor<?> ctor = constructor.getConstructor();
401402
Class<?>[] parameterTypes = ctor.getParameterTypes();
403+
List<? extends Parameter<Object, ?>> parameters = constructor.getParameters();
402404

403405
for (int i = 0; i < parameterTypes.length; i++) {
404406

@@ -409,6 +411,11 @@ private void visitCreateMethod(ClassWriter cw, PersistentEntity<?, ?> entity,
409411
mv.visitInsn(AALOAD);
410412

411413
if (parameterTypes[i].isPrimitive()) {
414+
415+
mv.visitInsn(DUP);
416+
String parameterName = parameters.size() > i ? parameters.get(i).getName() : null;
417+
418+
insertAssertNotNull(mv, parameterName == null ? String.format("at index %d", i) : parameterName);
412419
insertUnboxInsns(mv, Type.getType(parameterTypes[i]).toString().charAt(0), "");
413420
} else {
414421
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(parameterTypes[i]));
@@ -438,6 +445,20 @@ private static void visitArrayIndex(MethodVisitor mv, int idx) {
438445
mv.visitLdcInsn(idx);
439446
}
440447

448+
/**
449+
* Insert not {@literal null} assertion for a parameter.
450+
*
451+
* @param mv the method visitor into which instructions should be inserted
452+
* @param parameterName name of the parameter to create the appropriate assertion message.
453+
*/
454+
private void insertAssertNotNull(MethodVisitor mv, String parameterName) {
455+
456+
// Assert.notNull(property)
457+
mv.visitLdcInsn(String.format("Parameter %s must not be null!", parameterName));
458+
mv.visitMethodInsn(INVOKESTATIC, "org/springframework/util/Assert", "notNull",
459+
String.format("(%s%s)V", String.format("L%s;", JAVA_LANG_OBJECT), "Ljava/lang/String;"), false);
460+
}
461+
441462
/**
442463
* Insert any necessary cast and value call to convert from a boxed type to a primitive value.
443464
* <p>

src/test/java/org/springframework/data/convert/ClassGeneratingEntityInstantiatorUnitTests.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,17 @@ public void instantiateObjectCtor1ParamInt() {
264264
});
265265
}
266266

267+
@Test // DATACMNS-1200
268+
public void instantiateObjectCtor1ParamIntWithoutValue() {
269+
270+
doReturn(ObjectCtor1ParamInt.class).when(entity).getType();
271+
doReturn(PreferredConstructorDiscoverer.discover(ObjectCtor1ParamInt.class))//
272+
.when(entity).getPersistenceConstructor();
273+
274+
assertThatThrownBy(() -> this.instance.createInstance(entity, provider)) //
275+
.hasCauseInstanceOf(IllegalArgumentException.class);
276+
}
277+
267278
@Test // DATACMNS-578, DATACMNS-1126
268279
@SuppressWarnings("unchecked")
269280
public void instantiateObjectCtor7ParamsString5IntsString() {

0 commit comments

Comments
 (0)