package ru.csu.stan.java.classgen.util; import java.math.BigInteger; import java.util.HashSet; import java.util.List; import java.util.Set; import ru.csu.stan.java.classgen.automaton.ClassContext; import ru.csu.stan.java.classgen.jaxb.AggregatedType; import ru.csu.stan.java.classgen.jaxb.BaseTypedElement; import ru.csu.stan.java.classgen.jaxb.Class; import ru.csu.stan.java.classgen.jaxb.Classes; import ru.csu.stan.java.classgen.jaxb.CommonType; import ru.csu.stan.java.classgen.jaxb.ObjectFactory; import ru.csu.stan.java.classgen.jaxb.ParentClass; public class ClassNameResolver { private ImportRegistry imports; private PackageRegistry packages; private ClassNameResolver(ClassContext context){ this.imports = context.getImpReg(); this.packages = context.getPackageReg(); } public static ClassNameResolver getInstance(ClassContext context){ return new ClassNameResolver(context); } /** * Получение полного имени типа. * @param name исходное имя класса (может уже быть полным). * @param currentClass текущий обрабатываемый класс, в котором выполняется поиск полного имени типа. * @param allClasses все классы проекта. * @return полное имя типа, null - если в проекте не описан соответствующий тип. */ public String getFullTypeName(String name, Class currentClass, Classes allClasses) { // все по простому: класс нормально импортирован из проекта if (packages.isClassInRegistry(name)) return name; // всякие сложности else{ return findFullClassNameInProject(name, currentClass, allClasses); } } /** * Поиск полного типа класса внутри исследуемого проекта. * @param name * @param currentClass * @param allClasses * @return */ private String findFullClassNameInProject(String name, Class currentClass, Classes allClasses) { // Получаем метаданные о файле сборки CompilationUnit unit = imports.findUnitByClass(currentClass.getName()); if (packages.isClassInRegistry(currentClass.getName() + '.' + name)) return currentClass.getName() + '.' + name; String currentPackageName = findNameInCurrentPackage(name, unit); if (currentPackageName != null) return currentPackageName; String starImportedName = findNameInStarImports(name, unit); if (starImportedName != null) return starImportedName; return findNameInContainerClass(name, currentClass, allClasses, unit); } /** * Получение полного имени из класса, для которого текущий является вложенным. * Если текущий вложенным не является, тогда результат будет null. * @param name * @param currentClass * @param allClasses * @param unit * @return */ private String findNameInContainerClass(String name, Class currentClass, Classes allClasses, CompilationUnit unit) { String localCurrentClassName = currentClass.getName().substring(unit.getPackageName().length()+1); if (localCurrentClassName.indexOf('.') > 0){ Set<String> sameThings = getAllFullNamesWithSameBeginningAndEnding(name, unit); if (sameThings.size() > 1){ String fullTypeName = resolveNameInContainerClassParent(allClasses.getClazz(), unit.getPackageName(), localCurrentClassName, name, sameThings); if (fullTypeName != null && !fullTypeName.isEmpty()){ return fullTypeName; } } if (sameThings.size() == 1){ return sameThings.iterator().next(); } } return null; } /** * @param name * @param unit * @return */ private Set<String> getAllFullNamesWithSameBeginningAndEnding(String name, CompilationUnit unit) { Set<String> sameThings = new HashSet<String>(); for (String imp : unit.getImports()) sameThings.addAll(packages.getClassesByPrefixAndPostfix(imp, name)); sameThings.addAll(packages.getClassesByPrefixAndPostfix(unit.getPackageName(), name)); return sameThings; } /** * @param name * @param unit */ private String findNameInStarImports(String name, CompilationUnit unit) { for (String starImport : unit.getStarImports()){ // отбрасываем ".*" String fullName = packages.findFullNameByShortInPackage(starImport.substring(0, starImport.length()-2), name); if (fullName != null){ return fullName; } } return null; } /** * Поиск имени в текущем пакете. * @param name * @param unit */ private String findNameInCurrentPackage(String name, CompilationUnit unit) { String fullName = packages.findFullNameByShortInPackage(unit.getPackageName(), name); if (fullName != null){ return fullName; } return null; } /** * Поиск в наборе строк тех, что имеют заданное окончание. * @param strings набор строк для поиска. * @param ending окончание, по которому идет поиск. * @return Набор строк, подобранных среди исходного. */ private Set<String> searchForEnding(Set<String> strings, String ending){ Set<String> result = new HashSet<String>(); for (String str : strings) if (str.endsWith(ending)) result.add(str); return result; } /** * Попытка получение полного имени объемлющего класса. * @param classes * @param packageName * @param localClassName * @param name * @param candidates * @return */ private String resolveNameInContainerClassParent(List<Class> classes, String packageName, String localClassName, String name, Set<String> candidates){ if (localClassName.lastIndexOf('.') == -1) return null; String containerClassName = localClassName.substring(0, localClassName.lastIndexOf('.')); String searchClass = packageName + '.' + containerClassName; for (Class cl : classes) if (cl.getName().equals(searchClass)) for (ParentClass parentCl : cl.getParent()){ String searchingNameInContainersParent = name; if (parentCl.getName().lastIndexOf('.') > 0) searchingNameInContainersParent = parentCl.getName().substring(parentCl.getName().lastIndexOf('.')+1, parentCl.getName().length()-1) + '.' + searchingNameInContainersParent; else searchingNameInContainersParent = parentCl.getName() + '.' + searchingNameInContainersParent; Set<String> sameEndings = searchForEnding(candidates, searchingNameInContainersParent); if (sameEndings.size() > 1) return resolveNameInContainerClassParent(classes, packageName, containerClassName, searchingNameInContainersParent, sameEndings); if (sameEndings.size() == 1) return sameEndings.iterator().next(); } return null; } /** * @param element * @param clazz * @param allClasses * @param objectFactory */ public void resolveTypeNames(BaseTypedElement element, Class clazz, Classes allClasses, ObjectFactory objectFactory) { List<CommonType> type = element.getCommonType(); if (type != null && type.size() > 0){ String fullTypeName = getFullTypeName(type.get(0).getName(), clazz, allClasses); if (fullTypeName != null && !fullTypeName.isEmpty()){ type.get(0).setName(fullTypeName); } else element.getCommonType().clear(); } List<AggregatedType> aType = element.getAggregatedType(); if (aType != null && aType.size() > 0){ String fullTypeName = getFullTypeName(aType.get(0).getName(), clazz, allClasses); String fullAgregatedTypeName = getFullTypeName(aType.get(0).getElementType(), clazz, allClasses); if (fullTypeName != null && !fullTypeName.isEmpty()){ element.getAggregatedType().clear(); CommonType newType = objectFactory.createCommonType(); newType.setName(fullTypeName); element.getCommonType().add(newType); } else if (fullAgregatedTypeName != null && !fullAgregatedTypeName.isEmpty()) { aType.get(0).setElementType(fullAgregatedTypeName); aType.get(0).setId(BigInteger.valueOf(-1)); } else element.getAggregatedType().clear(); } } }