package org.incha.compiler.dom; import java.io.File; import java.lang.reflect.Field; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IPackageDeclaration; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.internal.compiler.SourceElementParser; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; import org.eclipse.jdt.internal.core.CompilationUnitElementInfo; import org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor; import org.eclipse.jdt.internal.core.JavaModelManager; import org.incha.ui.TaskProgressMonitor; import org.incha.ui.util.NullMonitor; import org.incha.ui.util.SubProgressMonitor; /** * Parser and builder of tree of java elements * */ public class JavaDomBuilder { private final CompilerOptions options; private final String javaProject; private static JavaModelCacheExt cache = initializeJavaModelManager(); /** * */ public JavaDomBuilder(final String javaProject, final String javaLevel) { super(); //set compiler options. final Map<?, ?> opts = JavaCore.getOptions(); JavaCore.setComplianceOptions(javaLevel, opts); options = new CompilerOptions(opts); this.javaProject = javaProject; } /** * Factory method to create the dom builder * @param file file to parse. */ public JavaDomBuilder(final String javaProject) { this(javaProject, JavaCore.VERSION_1_7); } /** * Builds the ICompilationUnit updating the progressMonitor * @param file The file * @param progressMonitor progress monitor. * @return the type. */ public ICompilationUnit build(final File file, final TaskProgressMonitor progressMonitor) { final TaskProgressMonitor subMonitor = progressMonitor == null ? new NullMonitor() : new SubProgressMonitor(progressMonitor); subMonitor.beginTask("Compile file " + file.getName(), 1); try { return build(file); } finally { subMonitor.done(); } } /** * Builds the ICompilationUnit * @param file * @return the type */ protected ICompilationUnit build(final File file) { final SimpleCompilationUnit u = new SimpleCompilationUnit(javaProject, file); final SourceElementParser sourceParser = new SourceElementParser(null, new DefaultProblemFactory(), options, true, false); final Map<Object, Object> localInfo = new HashMap<Object, Object>(); final CompilationUnitStructureRequestor requester = new CompilationUnitStructureRequestor(u, new CompilationUnitElementInfo(), localInfo){ { this.parser = sourceParser; } }; sourceParser.setRequestor(requester); sourceParser.parseCompilationUnit(u, true, new NullProgressMonitor()); //search and set compiled element name to simple package fragment. final IPackageDeclaration p = searchCompiledPackageFragment(localInfo); u.setPackageName(p.getElementName()); //merge compilation info for (final Map.Entry<Object, Object> e : localInfo.entrySet()) { if (e.getKey() instanceof IJavaElement) { cache.putInfo((IJavaElement) e.getKey(), e.getValue()); } } //set roots to compilation unit final IJavaElement[] types = findAllChildren(localInfo.keySet()); u.setChildren(types); return u; } /** * @param keySet * @return */ private IJavaElement[] findAllChildren(final Set<Object> keySet) { final List<IJavaElement> list = new LinkedList<IJavaElement>(); for (final Object object : keySet) { final IJavaElement e = (IJavaElement) object; if (e.getParent() instanceof ICompilationUnit) { list.add(e); } } return list.toArray(new IJavaElement[list.size()]); } /** * @param map * @return */ private IPackageDeclaration searchCompiledPackageFragment( final Map<Object, Object> map) { for (final Object obj : map.keySet()) { if (obj instanceof IPackageDeclaration) { return (IPackageDeclaration) obj; } } return null; } /** * Ocupamos reflexion para cambiar en JavaModelManager el field de cache. * No es ideal ya que es reflection, pero no se encontro otra forma * @return */ private static JavaModelCacheExt initializeJavaModelManager() { try { // set up cache final Field cacheField = JavaModelManager.class.getDeclaredField("cache"); cacheField.setAccessible(true); final JavaModelCacheExt cache = new JavaModelCacheExt(); cacheField.set(JavaModelManager.getJavaModelManager(), cache); return cache; } catch (final Exception e) { e.printStackTrace(); return null; } } }