javaparser
javaparser copied to clipboard
record in an interface throw IllegalArgumentException
My Environment
javaparser 3.25.8
Current Behavior
When try to resolve a MethodCallExpr
got an exception.
Here is my test code for reproduce.
@Test
public void testStaticMethod() {
CompilationUnit compilationUnit = StaticJavaParser.parse("""
public interface IUtil {
record WrapperRecord(String name){}
}
public class Util implements IUtil {
public static Util create(String key) {
return new Util();
}
}
public class Test {
public void test() {
Util.create("foo");
}
}
""");
for (MethodDeclaration method : compilationUnit.findAll(MethodDeclaration.class)) {
for (MethodCallExpr call : method.findAll(MethodCallExpr.class)) {
String qualifiedSignature = call.resolve().getQualifiedSignature();
log.info("QualifiedSignature: {}", qualifiedSignature);
}
}
}
- Here is an interface named
IUtil
, and it has a record member. - A class named
Util
implementIUtil
. - A test class
Test
has a method callUtil.create()
.
The test code will throw an exception
java.lang.IllegalArgumentException: Cannot get a reference type declaration from com.github.javaparser.ast.body.RecordDeclaration
at com.github.javaparser.symbolsolver.JavaSymbolSolver.toTypeDeclaration(JavaSymbolSolver.java:426)
at com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.getTypeDeclaration(JavaParserFacade.java:698)
at com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserTypeAdapter.internalTypes(JavaParserTypeAdapter.java:196)
at com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserInterfaceDeclaration.internalTypes(JavaParserInterfaceDeclaration.java:366)
at com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration.hasInternalType(ResolvedTypeDeclaration.java:61)
at com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration.isAncestor(JavaParserClassDeclaration.java:396)
at com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration.getAncestors(JavaParserClassDeclaration.java:373)
at com.github.javaparser.symbolsolver.javaparsermodel.contexts.JavaParserTypeDeclarationAdapter.solveMethod(JavaParserTypeDeclarationAdapter.java:251)
at com.github.javaparser.symbolsolver.javaparsermodel.contexts.ClassOrInterfaceDeclarationContext.solveMethod(ClassOrInterfaceDeclarationContext.java:106)
at com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration.solveMethod(JavaParserClassDeclaration.java:329)
at com.github.javaparser.resolution.logic.MethodResolutionLogic.solveMethodInType(MethodResolutionLogic.java:887)
at com.github.javaparser.symbolsolver.javaparsermodel.contexts.MethodCallExprContext.solveMethod(MethodCallExprContext.java:161)
at com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.solve(JavaParserFacade.java:273)
at com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.solve(JavaParserFacade.java:134)
at com.github.javaparser.symbolsolver.JavaSymbolSolver.resolveDeclaration(JavaSymbolSolver.java:172)
at com.github.javaparser.ast.expr.MethodCallExpr.resolve(MethodCallExpr.java:319)
I tried to debug JP
. I found when resolve the method call(Util.create()
), JP
will get Util
ancestors and try get internal types.
In JavaParserTypeAdapter
, the record WrapperRecord
in IUtil
is instance of RecordDeclaration
, and then exception occurred.
public Set<ResolvedReferenceTypeDeclaration> internalTypes() {
// Use a special Set implementation that avoids calculating the hashCode of the node,
// since this can be very time-consuming for big node trees, and we are sure there are
// no duplicates in the members list.
Set<ResolvedReferenceTypeDeclaration> res = Collections.newSetFromMap(new IdentityHashMap<>());
for (BodyDeclaration<?> member : this.wrappedNode.getMembers()) {
if (member instanceof TypeDeclaration) {
res.add(JavaParserFacade.get(typeSolver).getTypeDeclaration((TypeDeclaration) member));
}
}
return res;
}
My Question
I want to know what did i wrong if i try to get the method qualified signature? Or dose JP
not support parsing record
in interfaces?
It seems to be a bug in the symbol solver. Records resolution is not fully supported in Symbol Solver.
It seems to be a bug in the symbol solver. Records resolution is not fully supported in Symbol Solver.
Thank you for the reply, will JP fix the issue next version?
The integration of Records resolution is a fairly lengthy process. It is very likely that this issue will not be corrected in the next version.
The integration of Records resolution is a fairly lengthy process. It is very likely that this issue will not be corrected in the next version.
Thank you for your reply.
Related to https://github.com/javaparser/javaparser/issues/3556#issuecomment-1102609775
The integration of Records resolution is a fairly lengthy process. It is very likely that this issue will not be corrected in the next version.
I'm not a developer of JP, but if I want to fix this, can anyone give me some guidance on how to do it and an estimate of how much time it takes?
Thank you for your offer, but it's currently under development.
@jlerbsc It would be incredibly helpful to have support for records as well. Do we have any timelines on when we can expect this fix?
Records resolution support is currently being developed. Thanks to @johannescoetzee for his contribution on this subject.
This will certainly be available in the next version, which will be released at the end of July.
@johannescoetzee can ensure that the resolution of the records takes this issue into account. Thank you for your help.
I've slightly modified the example given here to be java 8 compatible, to add some StaticJavaParser setup, and to allow automated testing:
@Test
@EnabledForJreRange(min = org.junit.jupiter.api.condition.JRE.JAVA_14)
public void testStaticMethod() {
ParserConfiguration.LanguageLevel oldLevel = StaticJavaParser.getParserConfiguration().getLanguageLevel();
StaticJavaParser.getParserConfiguration().setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_16);
StaticJavaParser.getParserConfiguration().setSymbolResolver(new JavaSymbolSolver(new ReflectionTypeSolver()));
CompilationUnit compilationUnit = StaticJavaParser.parse(
"public interface IUtil {\n" +
" record WrapperRecord(String name){}\n" +
"}\n" +
"\n" +
"public class Util implements IUtil {\n" +
" public static Util create(String key) {\n" +
" return new Util();\n" +
" }\n" +
"}\n" +
" \n" +
"public class Test {\n" +
" \n" +
" public void test() {\n" +
" Util.create(\"foo\");\n" +
" }\n" +
" \n" +
"}\n" );
StaticJavaParser.getParserConfiguration().setLanguageLevel(oldLevel);
for (MethodDeclaration method : compilationUnit.findAll(MethodDeclaration.class)) {
for (MethodCallExpr call : method.findAll(MethodCallExpr.class)) {
assertEquals("create", call.getNameAsString());
assertEquals("Util.create(java.lang.String)", call.resolve().getQualifiedSignature());
}
}
}
I can confirm this version passes on my branch. The only significant change I made that wasn't mentioned in the original report was adding the reflection symbol solver, but I don't think that explains the difference in results so I'm reasonably confident that this case is handled along with record resolution.
This bug has been fixed in the version currently under development. Thanks to @johannescoetzee