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

com.gs.dmn.runtime.compiler.JavaxToolsCompiler Maven / Gradle / Ivy

There is a newer version: 8.7.3
Show newest version
/*
 * Copyright 2016 Goldman Sachs.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations under the License.
 */
package com.gs.dmn.runtime.compiler;

import com.gs.dmn.feel.analysis.semantics.type.FunctionType;
import com.gs.dmn.feel.analysis.syntax.ast.FEELContext;
import com.gs.dmn.feel.analysis.syntax.ast.expression.function.FunctionDefinition;
import com.gs.dmn.feel.synthesis.FEELTranslator;
import com.gs.dmn.runtime.DMNRuntimeException;
import com.gs.dmn.transformation.basic.BasicDMN2JavaTransformer;
import org.apache.commons.lang3.StringUtils;

import javax.tools.*;
import javax.tools.JavaCompiler.CompilationTask;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class JavaxToolsCompiler extends JavaCompilerImpl {
    private final File classesDir;

    public JavaxToolsCompiler() {
        this(new File("."));
    }

    public JavaxToolsCompiler(File classesDir) {
        this.classesDir = classesDir;
    }

    @Override
    public ClassData makeClassData(FunctionDefinition element, FEELContext context, BasicDMN2JavaTransformer dmnTransformer, FEELTranslator feelTranslator, String libClassName) {
        FunctionType functionType = (FunctionType) element.getType();

        // Apply method parts
        String signature = "Object... args";
        boolean convertToContext = true;
        String body = feelTranslator.expressionToJava(element.getBody(), context);
        String applyMethod = dmnTransformer.applyMethod(functionType, signature, convertToContext, body);

        // Class parts
        String packageName = "com.gs.dmn.runtime";
        String className = "LambdaExpressionImpl";
        String returnType = dmnTransformer.toJavaType(dmnTransformer.convertType(functionType.getReturnType(), convertToContext));
        String javaClassText = classText(packageName, className, libClassName, returnType, applyMethod);

        return new JavaxToolsClassData(packageName, className, javaClassText);
    }

    private String classText(String packageName, String className, String lib, String returnType, String applyMethod) {
        return String.format(
                "package %s;\n" +
                "public class %s extends %s implements com.gs.dmn.runtime.LambdaExpression<%s> {\n" +
                "    %s" +
                "}",
                packageName, className, lib, returnType, applyMethod);
    }

    private String applyMethod(FunctionDefinition element, String returnType, String parametersAssignment, String body) {
        return String.format(
                "public %s apply() {" +
                        "%s" +
                        "return %s;" +
                        "}",
                returnType, parametersAssignment, body);
    }

    @Override
    public Class compile(ClassData classData) throws Exception {
        String packageName = classData.getPackageName();
        String className = classData.getClassName();
        String classText = ((JavaxToolsClassData)classData).getClassText();
        String qualifiedClassName = StringUtils.isBlank(packageName) ? className : packageName + "." + className;

        // Initialize compiler
        javax.tools.JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector diagnosticCollector = new DiagnosticCollector<>();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnosticCollector, null, null);
        fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(classesDir));

        // Create java source file
        StringWriter writer = new StringWriter();
        PrintWriter out = new PrintWriter(writer);
        out.println(classText);
        out.close();
        JavaFileObject file = new JavaSourceFromString(qualifiedClassName, writer.toString());

        // Compile
        String[] compileOptions = new String[] {
                // set target folder
                "-d", classesDir.getAbsolutePath(),
                // set compiler's classpath to be same as the runtime's
                "-classpath", System.getProperty("java.class.path")
        };
        Iterable compilationUnits = Arrays.asList(file);
        CompilationTask task = compiler.getTask(null, fileManager, diagnosticCollector, Arrays.asList(compileOptions), null, compilationUnits);
        task.call();

        // Check diagnostics
        List> errors = diagnosticCollector.getDiagnostics().stream().filter(d -> d.getKind() == Diagnostic.Kind.ERROR).collect(Collectors.toList());
        if (!errors.isEmpty()) {
            throw new DMNRuntimeException(errors.toString());
        }

        // Load generated class
        ClassLoader classLoader = fileManager.getClassLoader(StandardLocation.CLASS_OUTPUT);
        return classLoader.loadClass(qualifiedClassName);
    }

    public static void main(String args[]) throws Exception {
        String text =
                "public class HelloWorld {" +
                        "    public static void main(String args[]) {" +
                        "       System.out.println(\"This is in another java file\");" +
                        "    }" +
                        "}";
        JavaxToolsClassData compilerArgs = new JavaxToolsClassData(null, "HelloWorld", text);
        Class cls = new JavaxToolsCompiler(new File(".")).compile(compilerArgs);

        try {
            cls.getDeclaredMethod("main", new Class[]{String[].class})
                    .invoke(null, new Object[]{null});
        } catch (NoSuchMethodException e) {
            System.err.println("No such method: " + e);
        } catch (IllegalAccessException e) {
            System.err.println("Illegal access: " + e);
        } catch (InvocationTargetException e) {
            System.err.println("Invocation target: " + e);
        }
    }

}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy