Interface returning generate object causes unsolved symbol exception
Hi,
I've been trying this out, and have run into a problem. I have a set of generated classes generated from avro IDL. When I try to create an interface that returns one of those generated classes, I get an unsolved symbol exception
e.g.
protocol Foo { import idl "Bar.avdl"; record Foo { Bar bar; string someData; } }
protocol Bar { record Bar { string someOtherData; } }
interface HasBar { getBar(); }
Now, if I generate the avro classes, and add implements HasBar manually to Foo.java, that works just fine. But, if I run ther interfacer task, that gives me the error If I instead have the interface with getsomeData() instead of getBar, that works fine.
Any ideas what is causing this, or is this a use case the library doesn't suport?
Could you share a stacktrace?
UnsolvedSymbolException{context='null', name='Bar', cause='null'}
at com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.convertClassOrInterfaceTypeToUsage(JavaParserFacade.java:713)
at com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.convertToUsage(JavaParserFacade.java:660)
at com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.convert(JavaParserFacade.java:798)
at com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserMethodDeclaration.getReturnType(JavaParserMethodDeclaration.java:79)
at com.github.javaparser.resolution.MethodUsage.
Let me know if you need anything else
If you reference generated class in interface, that won't work. You'll need to create another interface that is used in HasBar and use it as a return type:
protocol Foo {
import idl "Bar.avdl";
record Foo {
Bar bar;
string someData;
}
}
protocol Bar {
record Bar {
string someOtherData;
}
}
interface IBar {
String getSomeOtherData();
}
interface HasBar {
IBar getBar();
}
Ok, that's a decent work around.
But what if Bar is an IDL generated Enum instead? I don't see how you can avoid referencing it when that is literally where the enumeration is stored...
Protocol Bar { enum opts {a, b, c} }
Any suggestions?
Yeah, unfortunatly the work around doesn't actually work either.
interface HasBar { IBar getBar(); }
Still throws the unsolved symbol error.
This test suggests adding interfaces with methods returing other interfaces should work.
Could you post your maven config for the plugin?
Is IBar defined in same source folder as HasBar? What's the package for both?
Here's an example where I can't get it to work. https://github.com/WhiskyTangoFawks/interfacer-foobar
Build.gradle has the config IBar is defined in the same folder as HasBar (aka IFoo), and has the same package I have tried it with the generated classes in the same packages and the interfaces and in a different package, I get error either way
Task :interfacer FAILED Ok, we have the source /home/wayne/IdeaProjects/interfacer/src/main/java/com/test /home/wayne/IdeaProjects/interfacer/build/generated-main-avro-java/com/test/foobar dependencies: [DefaultExternalModuleDependency{group='org.apache.avro', name='avro', version='1.11.0', configuration='default'}] [parser adapter info] New source root at "/home/wayne/IdeaProjects/interfacer/build/generated-main-avro-java/com/test/foobar" [parser adapter info] New source root at "/home/wayne/IdeaProjects/interfacer/src/main/java/com/test" [parser adapter trace] Parsing /home/wayne/IdeaProjects/interfacer/src/main/java/com/test/foobar/IBar.java [parser adapter trace] Parsing /home/wayne/IdeaProjects/interfacer/src/main/java/com/test/foobar/IFoo.java UnsolvedSymbolException{context='null', name='IBar', cause='null'} at com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.convertClassOrInterfaceTypeToUsage(JavaParserFacade.java:713) at com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.convertToUsage(JavaParserFacade.java:660) at com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.convert(JavaParserFacade.java:798) at com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserMethodDeclaration.getReturnType(JavaParserMethodDeclaration.java:79) at com.github.javaparser.resolution.MethodUsage.
(MethodUsage.java:56) at com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration.getAllMethods(AbstractTypeDeclaration.java:50) at pl.matsuo.interfacer.model.ifc.TypeDeclarationIfcResolve.getMethods(TypeDeclarationIfcResolve.java:51) at pl.matsuo.interfacer.core.InterfacesAdder.lambda$scanInterfaces$0(InterfacesAdder.java:143) at java.base/java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:473) at java.base/java.util.TimSort.countRunAndMakeAscending(TimSort.java:355) at java.base/java.util.TimSort.sort(TimSort.java:220) at java.base/java.util.Arrays.sort(Arrays.java:1307) at java.base/java.util.ArrayList.sort(ArrayList.java:1721) at pl.matsuo.interfacer.core.InterfacesAdder.scanInterfaces(InterfacesAdder.java:144) at pl.matsuo.interfacer.core.InterfacesAdder.addInterfacesAllFiles(InterfacesAdder.java:112) at pl.matsuo.interfacer.core.InterfacesAdder.addInterfacesAllFiles(InterfacesAdder.java:82) at pl.matsuo.interfacer.core.InterfacesAdder$addInterfacesAllFiles.call(Unknown Source) at pl.matsuo.interfacer.gradle.InterfacerTask.addInterfaces(InterfacerTask.groovy:67) at jdk.internal.reflect.GeneratedMethodAccessor429.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104) at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58) at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51) at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$2.run(ExecuteActionsTaskExecuter.java:502) at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29) at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26) at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75) at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68) at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56) at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:74) at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:74) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:487) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:470) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.access$300(ExecuteActionsTaskExecuter.java:106) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.executeWithPreviousOutputFiles(ExecuteActionsTaskExecuter.java:271) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.execute(ExecuteActionsTaskExecuter.java:249) at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:89) at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:40) at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:53) at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:50) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195) at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75) at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:62) at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$call$2(DefaultBuildOperationExecutor.java:79) at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.callWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:54) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:79) at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:50) at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:40) at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:68) at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:38) at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:50) at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:36) at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:41) at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:74) at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55) at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:51) at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:29) at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:58) at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:39) at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:60) at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:27) at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:180) at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:75) at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:46) at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:40) at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:29) at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:36) at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:22) at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:105) at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$0(SkipUpToDateStep.java:98) at java.base/java.util.Optional.map(Optional.java:260) at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:53) at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:37) at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:85) at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:42) at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37) at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27) at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:92) at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:50) at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:114) at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:57) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:73) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:47) at org.gradle.internal.execution.steps.SkipEmptyWorkStep.lambda$execute$2(SkipEmptyWorkStep.java:92) at java.base/java.util.Optional.orElseGet(Optional.java:364) at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:92) at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:33) at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38) at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:43) at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:31) at org.gradle.internal.execution.steps.AssignWorkspaceStep.lambda$execute$0(AssignWorkspaceStep.java:40) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution$2.withWorkspace(ExecuteActionsTaskExecuter.java:284) at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:40) at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:30) at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:37) at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:27) at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:44) at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:33) at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:76) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:185) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:174) at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:109) at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46) at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51) at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57) at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56) at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195) at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75) at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:62) at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$call$2(DefaultBuildOperationExecutor.java:79) at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.callWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:54) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:79) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52) at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:74) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:402) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:389) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:382) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:368) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:127) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:191) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:182) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:124) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:61) at java.base/java.lang.Thread.run(Thread.java:833)
Execution failed for task ':interfacer'.
Unsolved symbol : IBar
- Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
I've checked your example.
First of all interfaceDirectory and scanDirectory should point to source roots (not subdirectories representing java packages), e.g.: file('src/main/java') not file('src/main/java/com/foobar/test').
After fixing it I've spotted that during interfacer plugin run there is a log from JavaParser generated here: https://github.com/javaparser/javaparser/blob/master/javaparser-core/src/main/java/com/github/javaparser/utils/SourceRoot.java#L185
It means that name of the folder containing classes that should be augmented, must be a valid java identifier. In your case it is generated-main-avro-java which is not a valid java identifier.
This shortcoming is derived from https://github.com/javaparser/javaparser.
I remember I had to do manual copy pasting before & after interfacer run to overcome it in gradle.
There is no plan to workaround it in this plugin at this moment.
I have been able to define an interface that returns a generated type based on Avro schema using gradle plugin. They key was to make sure the tasks are all run in correct order before the Java source is finally compiled:
apply plugin: "com.github.davidmc24.gradle.plugin.avro-base"
def generateProtocol = tasks.register("generateProtocol", GenerateAvroProtocolTask) {
source file("../schemas/avro/")
include("**/*.avdl")
outputDir = file("build/generated/avpr")
}
tasks.register("generateSchema", GenerateAvroSchemaTask) {
dependsOn generateProtocol
delete "../dist/schemas/avsc"
source file("../schemas/avro")
source file("build/generated/avpr")
include("**/*.avpr")
outputDir = file("../dist/schemas/avsc")
}
tasks.register("generate", GenerateAvroJavaTask) {
dependsOn generateSchema
source file("../dist")
include("**/*.avsc")
// Use Optional with the nullable fields (default is to not do this)
createOptionalGetters = true
optionalGettersForNullableFieldsOnly = true
outputDir = file("build/generated/java")
}
// The interfacer plugin allows us to post-process the generated Java source and apply interfaces defined in the src folder
tasks.register("avroInterfacer", pl.matsuo.interfacer.gradle.InterfacerTask) {
dependsOn generate
interfacePackage = 'com.domain.schema.core'
interfacesDirectory = file('src/main/java')
scanDirectory = file("build/generated/java")
}
// make sure that doing gradle build runs required tasks, this way it bundles in the module-info and checks everything works with junit test
tasks.withType(JavaCompile).configureEach {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
options.encoding = 'UTF-8'
it.dependsOn(avroInterfacer)
}