Как получить полное имя класса Java
У меня есть класс, как показано ниже.
public class Login {
private Keyword browser;
private String page;
}
Keyword
это класс в другой упаковке. Я хочу получить полное имя класса Keyword
при разборе Login
класс с использованием javaparser.
6 ответов
Вы можете использовать JavaParser Symbol Solver:
<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-symbol-solver-core</artifactId>
<version>3.14.5</version>
</dependency>
Затем проанализируйте код, используя следующую конфигурацию:
CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(new ReflectionTypeSolver(),
new JavaParserTypeSolver(sourceRoot));
final ParserConfiguration config = new ParserConfiguration()
.setStoreTokens(true)
.setSymbolResolver(new JavaSymbolSolver(combinedTypeSolver));
SourceRoot root = new SourceRoot(Paths.get("/path/to/project/"));
root.parse("", config, (Path localPath, Path absolutePath, ParseResult<CompilationUnit> result) -> {
// Do something with the CompilationUnit
return Result.DONT_SAVE;
});
Теперь мы можем получить полный идентификатор любого ReferenceType
с помощью:
ResolvedType type = referenceType.resolve();
String qualifiedName = type.getQualifiedName();
Вы не можете сделать это с помощью JavaParser, потому что JavaParser не разрешает символы. Чтобы преобразовать имя Keyword в класс, вам нужно сделать несколько вещей: * реализовать правильные правила области видимости (вам нужно искать внутренние классы, затем другие классы в том же файле, а затем рассматривать импорт...) * это зависит от путь к классу, используемый для компиляции: изменение одного и того же класса может быть разрешено по-разному
Для этого должен быть написан решатель символов: это не тривиально, а выполнимо. Если вас интересует эта тема, вы можете прочитать пост, который я только что написал Как создать решатель символов для Java в Clojure. Пост содержит также ссылку на код, свободно доступный на GitHub.
Источник: я участник JavaParser
Я написал метод, который может получить полное имя на основе ClassOrInterfaceDeclaration
объект (последняя версия JavaParser):
private static String getFullyQualifiedName(ClassOrInterfaceDeclaration c2) {
String name = "";
ClassOrInterfaceDeclaration parentClass = c2.getParentNode().isPresent() ? getClass(c2.getParentNode().get()): null;
if(parentClass!=null) {
name+=getFullyQualifiedName(parentClass)+".";
} else {
CompilationUnit u = getCompilationUnit(c2);
if(u!=null && u.getPackageDeclaration().isPresent()) {
name+=u.getPackageDeclaration().get().getNameAsString()+".";
}
}
return name+c2.getNameAsString();
}
private static ClassOrInterfaceDeclaration getClass(Node n1) {
while (!(n1 instanceof ClassOrInterfaceDeclaration)) {
if(n1.getParentNode().isPresent()) {
n1 = n1.getParentNode().get();
} else return null;
}
return (ClassOrInterfaceDeclaration)n1;
}
private static CompilationUnit getCompilationUnit(Node n1) {
while (!(n1 instanceof CompilationUnit)) {
if(n1.getParentNode().isPresent()) {
n1 = n1.getParentNode().get();
} else return null;
}
return (CompilationUnit)n1;
}
Гораздо более простая версия может быть использована, если вы получите ClassOrInterfaceType
класса:
private static String getFullyQualifiedName(ClassOrInterfaceType e) {
String name = "";
if(e.getScope().isPresent())
name+=getFullyQualifiedName(e.getScope().get())+".";
return name+e.getNameAsString();
}
Я надеюсь, что это поможет всем!
Никто до сих пор, похоже, не читал вопрос, но если вы анализируете исходный код, либо он находится в текущем пакете, либо он импортируется оператором импорта.
Я бы ожидал, что писатель или пользователь синтаксического анализатора Java будет знать это.
JavaParser не разрешает импорт (в любом случае это обычно не считается его работой). Вы должны вручную пройти через операторы импорта и искать, если Keyword
принадлежит им. Имейте в виду, что Java неявно делает import java.lang.*
в противном случае вы не будете разрешать такие типы, как String
,
Spring Roo имеет класс JavaParserUtils, содержащий метод getJavaType(CompilationUnitServices compilationUnitServices, ClassOrInterfaceDeclaration cid)
, Класс не предназначен для использования вне Roo, но вы можете использовать его как шаблон для решения вашей проблемы.
Если вы используете посетителей, кажется, что вы получаете только начальный и конечный индексы в исходном файле для того, чтобы иметь имя типа. Это не даст вам полное имя.
Таким образом, вы должны реализовать visit(ImportDeclaration, A)
Метод также в ваш пользовательский посетитель. Затем этот метод должен хранить объявления импорта, чтобы вы могли позже - когда метод visit(FieldDeclaration, A)
вызывается - обратитесь к импортированным пакетам и соберите полное имя.
Это может быть лучшим решением для вашей проблемы,
используя экземпляр.