Skip to content

Commit

Permalink
Avoid classes with incomplete hierarchy in Hibernate Validator
Browse files Browse the repository at this point in the history
  • Loading branch information
gastaldi committed May 2, 2024
1 parent e3e3950 commit 4c575b3
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package io.quarkus.hibernate.validator.test;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.AbstractCollection;

import jakarta.inject.Inject;
import jakarta.validation.Valid;
import jakarta.validation.Validator;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.ByteArrayAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.test.QuarkusUnitTest;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;

public class ClassHierarchyTest {

@RegisterExtension
static final QuarkusUnitTest test = new QuarkusUnitTest().setArchiveProducer(() -> {
JavaArchive javaArchive = ShrinkWrap.create(JavaArchive.class)
.addClass(Dto.class);
// Create an inner class with an incomplete hierarchy
try (DynamicType.Unloaded<?> superClass = new ByteBuddy()
.subclass(Object.class)
.name("SuperClass")
.make();
DynamicType.Unloaded<?> outerClass = new ByteBuddy()
.subclass(superClass.getTypeDescription())
.name("OuterClass")
.make();
DynamicType.Unloaded<?> innerClass = new ByteBuddy()
.subclass(AbstractCollection.class)
.innerTypeOf(outerClass.getTypeDescription())
.name("InnerClass")
.make();
DynamicType.Loaded<?> innerLoad = innerClass.load(Thread.currentThread().getContextClassLoader())) {
javaArchive.add(new ByteArrayAsset(innerLoad.getBytes()), "InnerClass.class");
}
return javaArchive;
});

@Inject
Validator validator;

@Test
public void doNotFailWhenLoadingIncompleteClassHierarchy() {
assertThat(validator).isNotNull();
}

@Valid
public static class Dto {
String name;

// InnerClass is a subclass with an incomplete hierarchy
@Valid
AbstractCollection<String> items;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
Expand Down Expand Up @@ -76,6 +77,9 @@ public void created(BeanContainer container) {
configuration.localeResolver(localeResolver);
}

// Filter out classes with incomplete hierarchy
filterIncompleteClasses(classesToBeValidated);

configuration.builtinConstraints(detectedBuiltinConstraints)
.initializeBeanMetaData(classesToBeValidated)
// Locales, Locale ROOT means all locales in this setting.
Expand Down Expand Up @@ -188,6 +192,22 @@ public void run() {
}
});
}

/**
* Filter out classes with incomplete hierarchy
*/
private void filterIncompleteClasses(Set<Class<?>> classesToBeValidated) {
Iterator<Class<?>> iterator = classesToBeValidated.iterator();
while (iterator.hasNext()) {
Class<?> clazz = iterator.next();
try {
// This should trigger a NoClassDefFoundError if the class has an incomplete hierarchy
clazz.getCanonicalName();
} catch (NoClassDefFoundError e) {
iterator.remove();
}
}
}
};

return beanContainerListener;
Expand Down

0 comments on commit 4c575b3

Please sign in to comment.