Generic class override behaviour

21 views
Skip to first unread message

Francisco Alejandro Lozano López

unread,
May 13, 2024, 8:13:40 AM5/13/24
to Byte Buddy
I have dynamically-generated model classes that I use in drools. It seems that these dynamically generated classes expose a different structure with regard to reflection than if they would have been defined by normal java code. I would like to understand why byte-buddy generates different byte-code and if I can control this behaviour, or if this is expected bytecode and drools "should" (if they decide so) support it.

These model classes have two base classes:

public abstract class Vehicle<TEngine extends Engine> {
    public abstract TEngine getEngine();
...
public abstract class Engine {

then I have an `engine` class:

engineClass = new ByteBuddy() .subclass(Engine.class).name("drools.issues.model.vehicles.GasolineEngine") //
...

and a vehicle class like this:

TypeDescription.Generic generic = TypeDescription.Generic.Builder.parameterizedType(Vehicle.class, engineClass).build(); vehicleClass = (Class<? extends Vehicle>) new ByteBuddy().subclass(generic) //.

If I do a subclass with normal Java code instead, drools works well:

public class DieselCar extends Vehicle<DieselEngine> {

but with my bytebuddy-generated class vehicleClass, I get:

java.lang.ClassCastException: class sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to class java.lang.Class (sun.reflect.generics.reflectiveObjects.TypeVariableImpl and java.lang.Class are in module java.base of loader 'bootstrap').

reflection of java class exposes an instance of Class always, so drools does a blind cast of Type to Class. However, bytebuddy-generated class exposes TypeVariableImpl instead. 

If I .subclass directly to Vehicle.class instead of the generic TypeDescriptor, drools does not complain (but the type information is not there, of course).

Any hint? is this way of subclassing for generics expected in byte-buddy? why is this different from java-compiler-generated class? are both "legal" java code? 


(FYI there's reproducing code of the drools issue https://github.com/apache/incubator-kie-drools/issues/5925

Rafael Winterhalter

unread,
May 13, 2024, 8:21:48 AM5/13/24
to Francisco Alejandro Lozano López, Byte Buddy
That's strange. Do you have a stack to that exception?

If you create a simple enough class, you can run "javap" on both the explicit class and the one created by Byte Buddy. Simply store the generated class file from the DynamicType to some file system location.

--
You received this message because you are subscribed to the Google Groups "Byte Buddy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to byte-buddy+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/byte-buddy/5fefe0c7-b740-4e19-809b-b44cd3b5d16dn%40googlegroups.com.

Francisco Alejandro Lozano López

unread,
May 13, 2024, 8:39:21 AM5/13/24
to Byte Buddy
I will try the javap approach and see the differences, thanks!

> Do you have a stack to that exception?

Yes, this is the exception. It's a drools exception, not byte-buddy, as I explained... so I assumed it would not be relevant, as it's drools who assumes this Type must always be a Class. 

class sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to class java.lang.Class (sun.reflect.generics.reflectiveObjects.TypeVariableImpl and java.lang.Class are in module java.base of loader 'bootstrap') java.lang.ClassCastException: class sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to class java.lang.Class (sun.reflect.generics.reflectiveObjects.TypeVariableImpl and java.lang.Class are in module java.base of loader 'bootstrap') at org.drools.model.codegen.execmodel.generator.drlxparse.SpecialComparisonCase.typeNeedsCast(SpecialComparisonCase.java:71) at org.drools.model.codegen.execmodel.generator.drlxparse.SpecialComparisonCase.specialComparisonFactory(SpecialComparisonCase.java:56) at org.drools.model.codegen.execmodel.generator.drlxparse.ConstraintParser.handleSpecialComparisonCases(ConstraintParser.java:900) at org.drools.model.codegen.execmodel.generator.drlxparse.ConstraintParser.parseBinaryExpr(ConstraintParser.java:712) at org.drools.model.codegen.execmodel.generator.drlxparse.ConstraintParser.compileToJavaRecursive(ConstraintParser.java:317) at org.drools.model.codegen.execmodel.generator.drlxparse.ConstraintParser.compileStart(ConstraintParser.java:269) at org.drools.model.codegen.execmodel.generator.drlxparse.ConstraintParser.drlxParse(ConstraintParser.java:164) at org.drools.model.codegen.execmodel.generator.visitor.pattern.ClassPatternDSL.findAllConstraint(ClassPatternDSL.java:188) at org.drools.model.codegen.execmodel.generator.visitor.pattern.PatternDSL.buildPattern(PatternDSL.java:62) at org.drools.model.codegen.execmodel.generator.visitor.ModelGeneratorVisitor.visit(ModelGeneratorVisitor.java:132) at org.drools.drl.ast.descr.PatternDescr.accept(PatternDescr.java:278) at org.drools.model.codegen.execmodel.generator.visitor.AndVisitor.visit(AndVisitor.java:52) at org.drools.model.codegen.execmodel.generator.visitor.ModelGeneratorVisitor.visit(ModelGeneratorVisitor.java:70) at org.drools.model.codegen.execmodel.generator.ModelGenerator.processRule(ModelGenerator.java:204) at org.drools.model.codegen.execmodel.generator.ModelGenerator.processRuleDescr(ModelGenerator.java:185) at org.drools.model.codegen.execmodel.generator.ModelGenerator.processRules(ModelGenerator.java:164) at org.drools.model.codegen.execmodel.generator.ModelGenerator.generateModel(ModelGenerator.java:130) at org.drools.model.codegen.execmodel.processors.ModelGeneratorPhase.process(ModelGeneratorPhase.java:48) at org.drools.compiler.builder.impl.processors.IteratingPhase.process(IteratingPhase.java:53) at org.drools.model.codegen.execmodel.processors.ModelMainCompilationPhase.process(ModelMainCompilationPhase.java:104) at org.drools.model.codegen.execmodel.ModelBuilderImpl.doSecondBuildStep(ModelBuilderImpl.java:114) at org.drools.compiler.builder.impl.CompositeKnowledgeBuilderImpl.build(CompositeKnowledgeBuilderImpl.java:125) at org.drools.compiler.builder.impl.CompositeKnowledgeBuilderImpl.build(CompositeKnowledgeBuilderImpl.java:109) at org.drools.compiler.kie.builder.impl.AbstractKieProject.buildKnowledgePackages(AbstractKieProject.java:274) at org.drools.compiler.kie.builder.impl.AbstractKieProject.buildKnowledgePackages(AbstractKieProject.java:220) at org.drools.compiler.kie.builder.impl.AbstractKieProject.verify(AbstractKieProject.java:84) at org.drools.compiler.kie.builder.impl.KieBuilderImpl.buildKieProject(KieBuilderImpl.java:285) at org.drools.compiler.kie.builder.impl.KieBuilderImpl.buildAll(KieBuilderImpl.java:251) at org.drools.compiler.kie.builder.impl.KieBuilderImpl.buildAll(KieBuilderImpl.java:208) at drools.issues.executor.DroolsInternalFactory.instanceKieContainer(DroolsInternalFactory.java:52) at drools.issues.executor.AbstractDroolsExecutor.<init>(AbstractDroolsExecutor.java:56) at drools.issues.executor.AbstractDroolsExecutor.<init>(AbstractDroolsExecutor.java:45) at drools.issues.executor.SingleStatefulSessionExecutor.<init>(SingleStatefulSessionExecutor.java:15) at drools.issues.AbstractTest.executor(AbstractTest.java:16) at drools.issues.DynamicClassTest.test(DynamicClassTest.java:39)

Test code is here: https://github.com/flozano/drools-issues/blob/main/src/test/java/drools/issues/DynamicClassTest.java
Reply all
Reply to author
Forward
0 new messages