Coder Social home page Coder Social logo

Comments (13)

mariofusco avatar mariofusco commented on June 3, 2024

I (sort of) see what you mean and we probably cannot give for granted that the Type is always a Class in that point, but at the moment I don't understand under which conditions it could be something else, and I really need a reproducer of this problem since I don't want to just develop a blind fix. Can you please just paste here the drl of a sample rule in your knowledge base that is causing this issue so I could try to create the isolated reproducer on my own?

from incubator-kie-drools.

flozano avatar flozano commented on June 3, 2024

I understand not wanting to fix blindly unless the scenario is clear.

The DRL is this:

package com.mycompany.myproject.engine.rules.model;
//generated from Decision Table
import com.mycompany.myproject.engine.rules.model.*;
global com.mycompany.myproject.engine.rules.model.ServerCodeRuntimeService serverCode;
dialect "mvel"
// rule values at B13, header at B8
rule "Tank Rules-SmartBIN_13"
	salience 65535
	when
		$asset: Sbtanknew_1_0_6($asset.devices.tank_device.properties.tanklevel_status != "Nearing Empty", $asset.devices.tank_device.readings.tank_level < $asset.properties.empty_fill_level_threshold)
	then
		$asset.getDevices().getTank_device().getProperties().setTanklevel_status("Nearing Empty");
		$asset.getDevices().getTank_device().getProperties().setTanklevel_color("Red");
		$asset.getProperties().setTank_level_status("CRITICAL");
		AlertMessage message = new AlertMessage("Nearing Empty");
		message.withParam("value", $asset.devices.tank_device.readings.tank_level);
		message.withParam("alias", "sb_device_tank_level");
		message.withParam("field", "Tank Level");
		message.withParam("is_required", "Required");
		insert(message);
end

if I drop $asset.devices.tank_device.readings.tank_level < $asset.properties.empty_fill_level_threshold, the above error goes away and a different one appears, but this one I need to investigate further. It also seems related to the fact that a generic class is involved. (I understand $asset inside the condition is redundant).

the model classes (eg:Sbtanknew_1_0_6) are derived from base classes and are runtime generated with byte-buddy, overriding several generic parameters of the parent class. I think this is where the issue comes from, and why it's not easy to isolate. I will try.

from incubator-kie-drools.

flozano avatar flozano commented on June 3, 2024

I have the feeling this could be related: https://issues.redhat.com/browse/DROOLS-7197, which I reported long time ago and was assumed to become a known issue partially documented in https://docs.drools.org/latest/drools-docs/drools/migration-guide/index.html

from incubator-kie-drools.

flozano avatar flozano commented on June 3, 2024

This is my attempt at reproducing it but no luck so far:
https://github.com/flozano/drools-issues/blob/main/src/test/java/drools/issues/DynamicClassTest.java

Classes are generated here dynamically in a similar way as I generate the ones causing trouble, with byte-buddy:
https://github.com/flozano/drools-issues/blob/main/src/main/java/drools/issues/model/vehicles/GasolineModelGenerator.java

and this DRL works well over them:
https://github.com/flozano/drools-issues/blob/main/src/test/resources/drools/issues/DynamicClassTest.drl

from incubator-kie-drools.

mariofusco avatar mariofusco commented on June 3, 2024

if I drop $asset.devices.tank_device.readings.tank_level < $asset.properties.empty_fill_level_threshold, the above error goes away and a different one appears, but this one I need to investigate further. It also seems related to the fact that a generic class is involved. (I understand $asset inside the condition is redundant).

Is there any reason why you're keeping that $asset inside the condition? Does it change anything if you remove it (I don't expect so, but just in case).

the model classes (eg:Sbtanknew_1_0_6) are derived from base classes and are runtime generated with byte-buddy, overriding several generic parameters of the parent class. I think this is where the issue comes from, and why it's not easy to isolate. I will try.

If the executable model generator can access the runtime classes generated by byte-buddy and introspect them during the code generation phase I believe that there shouldn't be any problem. My wild guess is that the executable model generator is introspecting the original classes before byte-buddy instrumentation and if so of course that's wrong and the root cause of the problem. Another (in my opinion more remote) possibility is that byte-buddy is rewriting the bytecode of the domain model classes in a way that for some reason prevents the introspection necessary for the executable model generation, but if so we would also need a reproducer for that.

from incubator-kie-drools.

flozano avatar flozano commented on June 3, 2024

Thanks for answering!

Is there any reason why you're keeping that $asset inside the condition? Does it change anything if you remove it (I don't expect so, but just in case).

I'm keeping because the original DRL had it and I wanted to reproduce exactly - but no, it doesn't change anything. I mentioned in:

(I understand $asset inside the condition is redundant).

With regard to:

If the executable model generator can access the runtime classes generated by byte-buddy and introspect them during the code generation phase I believe that there shouldn't be any problem.

I believe so too. I use the correct strategy in byte-buddy (ClassLoadingStrategy.Default.CHILD_FIRST_PERSISTENT) and expose the right class-loader to drools... so everything is there for drools to access.

update

I just reproduced it, you can find the failing version here: https://github.com/flozano/drools-issues/blob/main/src/test/java/drools/issues/DynamicClassTest.java

The changes to reproduce:
After properly subclassing in byte-buddy with the generic type descriptor instead of the raw Vehicle class,
and using the property getter defined in the parent item (motor instead of engine), I expected to find same issue as in #5932 (https://issues.redhat.com/browse/DROOLS-7197), but I didn't, I reproduced this.

full stack-trace

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)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestTemplateMethod(TimeoutExtension.java:92)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:226)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:204)
	at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:139)
	at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.lambda$execute$2(TestTemplateTestDescriptor.java:107)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
	at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1939)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
	at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1708)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
	at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1708)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
	at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:107)
	at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:42)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:119)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:94)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:89)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:62)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
	at jdk.proxy1/jdk.proxy1.$Proxy2.stop(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
	at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)


from incubator-kie-drools.

mariofusco avatar mariofusco commented on June 3, 2024

I will try to give a look at that reproducer asap, but what I don't understand is why it is not possible to create the same reproducer in a more isolated way and without byte-buddy. I mean once you have done the byte-buddy instrumentation those generated classes should be indistinguishable from classes generated by a normal compilation. In essence what I'm suggesting is that it should be possible to also reproduce the same problem with a plain Java domain model that incorporates in its source the changes made at bytecode level by byte-buddy. Am I making sense? Do you think it would be possible to create such a reproducer?

from incubator-kie-drools.

flozano avatar flozano commented on June 3, 2024

I agree with you that it should be possible, but if you look at what my byte-buddy code does, it should be the same already...

Base

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

"Diesel" model, 'normal' java compilation-generated classes

public class DieselCar extends Vehicle<DieselEngine> {
// ...
	public DieselEngine getEngine() {
		return engine;
	}
// ...
public class DieselEngine extends Engine {

"Gasoline" model, byte-buddy generated classes

engineClass = new ByteBuddy()
	.subclass(Engine.class).name("drools.issues.model.vehicles.GasolineEngine") //
	.method(ElementMatchers.named("isZeroEmissions")) //
	.intercept(FixedValue.value(false)) //
	.defineProperty("highOctane", boolean.class) //
	.defineProperty("maxTorque", int.class) //
	.defineProperty("serialNumber", long.class) //
	.make().load(classLoader, ClassLoadingStrategy.Default.CHILD_FIRST_PERSISTENT).getLoaded();
TypeDescription.Generic generic = TypeDescription.Generic.Builder.parameterizedType(Vehicle.class, engineClass).build();
vehicleClass = (Class<? extends Vehicle>) new ByteBuddy() //
		// .subclass(Vehicle.class) //
		.subclass(generic)
		.name("drools.issues.model.vehicles.GasolineVehicle") //
		.defineField("engine", engineClass, Visibility.PRIVATE) //
		.defineConstructor(Visibility.PUBLIC) //
		.withParameters(String.class, String.class, engineClass) //
		.intercept(MethodCall.invoke(Vehicle.class.getDeclaredConstructor(String.class, String.class))
				.withArgument(0, 1) //
				.andThen(FieldAccessor.ofField("engine").setsArgumentAt(2)) //
		) //
		.defineMethod("getEngine", engineClass, Visibility.PUBLIC) //
		.intercept(FieldAccessor.ofField("engine")) //
		.defineProperty("frameMaxTorque", long.class) //
		.make().load(classLoader, ClassLoadingStrategy.Default.CHILD_FIRST_PERSISTENT).getLoaded();

the byte-buddy generated class is legal JVM code that can be executed. I can dispatch invocations to parent class (Engine) methods, subclass (DieselEngine) methods... as per the JVM this should be legal code, I believe.

from incubator-kie-drools.

flozano avatar flozano commented on June 3, 2024

from byte-buddy, it very explicitly supports subclasses of generic parents:

    /**
     * <p>
     * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
     * this interface type is created.
     * </p>
     * <p>
     * When extending a class, Byte Buddy imitates all visible constructors of the subclassed type and sets them to be {@code public}.
     * Any constructor is implemented to only invoke its super type constructor of equal signature. Another behavior can be specified by
     * supplying an explicit {@link ConstructorStrategy} by {@link ByteBuddy#subclass(TypeDefinition, ConstructorStrategy)}.
     * </p>
     * <p>
     * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link TypeDescription} values are implemented
     * as raw types if they declare type variables.
     * </p>
     * <p>
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
     * types, a external cache or {@link TypeCache} should be used.
     * </p>
     *
     * @param superType The super class or interface type to extend. The type must be a raw type or parameterized type. All type
     *                  variables that are referenced by the generic type must be declared by the generated subclass before creating
     *                  the type.
     * @return A type builder for creating a new class extending the provided class or interface.
     */
    public DynamicType.Builder<?> subclass(TypeDefinition superType) {
        return subclass(superType, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING);
    }

superType The super class or interface type to extend. The type must be a raw type or parameterized type. All type variables that are referenced by the generic type must be declared by the generated subclass before creating the type.

from incubator-kie-drools.

flozano avatar flozano commented on June 3, 2024

(just pushed a small fix for another unrelated method which was declared package-private but public in the byte-buddy. it has no effect on this specific test and case).

from incubator-kie-drools.

flozano avatar flozano commented on June 3, 2024

@mariofusco after you pushed for checking this better, I verified I could also reproduce this with non-byte-buddy classes:

https://github.com/flozano/drools-issues/blob/main/src/test/java/drools/issues/DynamicClassTest.java#L26

I copied the test and replicated it with DieselCar/Engine, which are normal java classes.

from incubator-kie-drools.

mariofusco avatar mariofusco commented on June 3, 2024

Fixed by 785ef86

from incubator-kie-drools.

flozano avatar flozano commented on June 3, 2024

Thanks a lot! I will verify once the SNAPSHOT is built.

The same test incidentally raised #5943, will check that one too.

from incubator-kie-drools.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.