All Downloads are FREE. Search and download functionalities are using the official Maven repository.

play.template2.compile.GTJavaCompileToClass Maven / Gradle / Ivy

Go to download

RePlay is a fork of the Play1 framework, made and maintained by Codeborne.

The newest version!
package play.template2.compile;


import org.apache.commons.io.IOUtils;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.*;
import org.eclipse.jdt.internal.compiler.Compiler;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import play.template2.exceptions.GTCompilationException;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;

import static org.apache.commons.io.IOUtils.closeQuietly;

public class GTJavaCompileToClass {

    private final ClassLoader parentClassLoader;

    Map packagesCache = new HashMap<>();

    Map settings;

    /**
     * Try to guess the magic configuration options
     */
    public GTJavaCompileToClass(ClassLoader parentClassLoader) {
        this.parentClassLoader = parentClassLoader;
        this.settings = new HashMap<>();
        this.settings.put(CompilerOptions.OPTION_ReportMissingSerialVersion, CompilerOptions.IGNORE);
        this.settings.put(CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.GENERATE);
        this.settings.put(CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.GENERATE);
        this.settings.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.IGNORE);
        this.settings.put(CompilerOptions.OPTION_ReportUnusedImport, CompilerOptions.IGNORE);
        this.settings.put(CompilerOptions.OPTION_Encoding, "UTF-8");
        this.settings.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.DO_NOT_GENERATE);
        this.settings.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_8);
        this.settings.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_8);
        this.settings.put(CompilerOptions.OPTION_PreserveUnusedLocal, CompilerOptions.OPTIMIZE_OUT);
        this.settings.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_8);
    }

    /**
     * Something to compile
     */
    static final class CompilationUnit implements ICompilationUnit {

        private final String fileName;
        private final char[] typeName;
        private final char[][] packageName;
        private final String source;

        CompilationUnit(String pClazzName, String source) {
            fileName = pClazzName.replaceAll("\\.", "/") + ".java";//bogus
            int dot = pClazzName.lastIndexOf('.');
            if (dot > 0) {
                typeName = pClazzName.substring(dot + 1).toCharArray();
            } else {
                typeName = pClazzName.toCharArray();
            }
            StringTokenizer izer = new StringTokenizer(pClazzName, ".");
            packageName = new char[izer.countTokens() - 1][];
            for (int i = 0; i < packageName.length; i++) {
                packageName[i] = izer.nextToken().toCharArray();
            }

            this.source = source;
        }

        @Override public char[] getFileName() {
            return fileName.toCharArray();
        }

        @Override public char[] getContents() {
            return source.toCharArray();
        }

        @Override public char[] getMainTypeName() {
            return typeName;
        }

        @Override public char[][] getPackageName() {
            return packageName;
        }

        @Override public boolean ignoreOptionalProblems() {
            return false;
        }
    }

    /**
         * Compilation result
         */
    public static class MyICompilerRequestor implements ICompilerRequestor {

        public CompiledClass[] compiledClasses;


        @Override public void acceptResult(CompilationResult result) {
            // If error
            if (result.hasErrors()) {
                for (IProblem problem: result.getErrors()) {
                    String className = new String(problem.getOriginatingFileName()).replace("/", ".");
                    className = className.substring(0, className.length() - 5);
                    String message = problem.getMessage();
                    if (problem.getID() == IProblem.CannotImportPackage) {
                        // Non sense !
                        message = problem.getArguments()[0] + " cannot be resolved";
                    }
                    throw new GTCompilationException("Compile error. classname: " + className + ". message: " + message + " ln: " + problem.getSourceLineNumber());
                }
            }
            // Something has been compiled
            compiledClasses = new CompiledClass[result.getClassFiles().length];
            ClassFile[] clazzFiles = result.getClassFiles();
            for (int i = 0; i < clazzFiles.length; i++) {
                ClassFile clazzFile = clazzFiles[i];
                char[][] compoundName = clazzFile.getCompoundName();
                StringBuilder clazzName = new StringBuilder();
                for (int j = 0; j < compoundName.length; j++) {
                    if (j != 0) {
                        clazzName.append('.');
                    }
                    clazzName.append(compoundName[j]);
                }

                compiledClasses[i] = new CompiledClass(clazzName.toString(), clazzFile.getBytes());
            }

        }
    }


    public static class CompiledClass {
        public final String classname;
        public final byte[] bytes;

        public CompiledClass(String classname, byte[] bytes) {
            this.classname = classname;
            this.bytes = bytes;
        }
    }

    /**
     * Please compile this className
     */
    @SuppressWarnings("deprecation")
    public CompiledClass[] compile(String className, String source) {

        ICompilationUnit compilationUnits = new CompilationUnit(className, source);
        IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies.exitOnFirstError();
        IProblemFactory problemFactory = new DefaultProblemFactory(Locale.ENGLISH);

        /*
         * To find types ...
         */
        INameEnvironment nameEnvironment = new INameEnvironment() {

            @Override public NameEnvironmentAnswer findType(final char[][] compoundTypeName) {
                StringBuilder result = new StringBuilder();
                for (int i = 0; i < compoundTypeName.length; i++) {
                    if (i != 0) {
                        result.append('.');
                    }
                    result.append(compoundTypeName[i]);
                }
                return findType(result.toString());
            }

            @Override public NameEnvironmentAnswer findType(final char[] typeName, final char[][] packageName) {
                StringBuilder result = new StringBuilder();
                for (char[] aPackageName : packageName) {
                    result.append(aPackageName);
                    result.append('.');
                }
                result.append(typeName);
                return findType(result.toString());
            }

            private NameEnvironmentAnswer findType(final String name) {
                String resourceName = name.replace(".", "/") + ".class";
                InputStream is = parentClassLoader.getResourceAsStream(resourceName);
                if (is == null) {
                    return null;
                }

                byte[] bytes;
                try {
                    bytes = IOUtils.toByteArray(is);
                }
                catch (IOException e) {
                    throw new GTCompilationException(e);
                }
                finally {
                    closeQuietly(is);
                }
                try {
                    ClassFileReader classFileReader = new ClassFileReader(bytes, name.toCharArray(), true);
                    return new NameEnvironmentAnswer(classFileReader, null);
                }
                catch (ClassFormatException e) {
                    throw new GTCompilationException("Failed to load class " + name, e);
                }
            }

            @Override
            public boolean isPackage(char[][] parentPackageName, char[] packageName) {
                // Rebuild something usable
                StringBuilder sb = new StringBuilder();
                if (parentPackageName != null) {
                    for (char[] p : parentPackageName) {
                        sb.append(new String(p));
                        sb.append(".");
                    }
                }

                String child = new String(packageName);
                sb.append(".");
                sb.append(child);
                String name = sb.toString();

                boolean isPackage;

                // Currently there is no complete package dictionary so a couple of simple
                // checks hopefully suffices.
                if (Character.isUpperCase(child.charAt(0))) {
                    // Typically only a class begins with a capital letter.
                    isPackage = false;
                }
                else if (packagesCache.containsKey(name)) {
                    // Check the cache if this was a class identified earlier.
                    isPackage = packagesCache.get(name);
                }
                else {
                    // Does there exist a class with this name?
                    boolean isClass = false;
                    try {
                        parentClassLoader.loadClass(name);
                        isClass = true;
                    }
                    catch (Exception e) {
                        // nop
                    }

                    isPackage = !isClass;
                    packagesCache.put(name, isPackage);
                }

                return isPackage;
            }

            @Override
            public void cleanup() {
            }
        };

        MyICompilerRequestor compilerRequestor = new MyICompilerRequestor();


        /*
         * The JDT compiler
         */
        Compiler jdtCompiler = new Compiler(nameEnvironment, policy, settings, compilerRequestor, problemFactory) {

            @Override
            protected void handleInternalException(Throwable e, CompilationUnitDeclaration ud, CompilationResult result) {
            }
        };

        // Go !
        jdtCompiler.compile( new ICompilationUnit[]{compilationUnits});

        return compilerRequestor.compiledClasses;

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy