简体   繁体   English

以编程方式将 java 代码添加到现有 java 文件的任何可能方法?

[英]Any possible ways to add a java code to existing java file programatically?

I have an interface and class file auto-generated using a custom maven plugin I created.我有一个使用我创建的自定义 maven 插件自动生成的接口和 class 文件。 The plugin will read the necessary data from a JSON file and create me a Java files using Jenesis4Java (Mojo code provided below).该插件将从 JSON 文件中读取必要的数据,并使用 Jenesis4Java(下面提供的 Mojo 代码)为我创建一个 Java 文件。

REQUIREMENT - i have to traverse to the already generated file and add a new method or code in that file.要求- 我必须遍历已生成的文件并在该文件中添加新方法或代码。 Is there any way to achieve this from Mojo?有什么方法可以从 Mojo 实现这一目标吗? Take a look at below generated code, so I have to add a new abstract method to it.看看下面生成的代码,所以我必须向它添加一个新的抽象方法。

I can only regenerate the same file from beginning but not able to add to existing code.我只能从头开始重新生成同一个文件,但不能添加到现有代码中。

The following code was generated-生成了以下代码-

   /**
 * Customer360 interface.
 */

import java.io.Serializable;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

import javax.ws.rs.core.*;

import reactor.core.publisher.Mono;


@Path(value = "/")
public interface Customer360 {
    @GET
    @Path(value = "")
    @Produces(value = "application/json")
    Mono<Response> casecreation(@Context
    HttpHeaders httpHeaders, @Context
    UriInfo uriInfo);

    @GET
    @Path(value = "")
    @Produces(value = "application/json")
    Mono<Response> getCustomerDetails(@Context
    HttpHeaders httpHeaders, @Context
    UriInfo uriInfo);

    @GET
    @Path(value = "")
    @Produces(value = "application/json")
    Mono<Response> prefetch(@Context
    HttpHeaders httpHeaders, @Context
    UriInfo uriInfo);
}

In the mojo file I have written the logic to generate this and another class file.在 mojo 文件中,我编写了生成此文件和另一个 class 文件的逻辑。 (Mojo refers to java file in maven plugin creation process) (Mojo参考maven插件创建过程中的java文件)

Mojo file for reference- Mojo 文件供参考-

import net.sf.json.JSONSerializer;
import net.sourceforge.jenesis4java.*;
import net.sourceforge.jenesis4java.impl.MCodeWriter;
import net.sourceforge.jenesis4java.jaloppy.JenesisJalopyEncoder;
import org.apache.commons.io.IOUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;

import java.awt.*;
import java.io.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

//import reactor.core.publisher.Mono;


import java.util.Iterator;
import java.util.Map;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.*;

@Mojo(name = "generate-code", defaultPhase = LifecyclePhase.COMPILE)
public class GenerateApiResource extends AbstractMojo {

    @Parameter(defaultValue = "${project}", required = true, readonly = true)
    MavenProject project;

    @Parameter(defaultValue = "src/main/java", required = true)
    protected File outputJavaDirectory;

    @Parameter(defaultValue = "src/main/java", required = true)
    protected File outputJavaDirectory2;

    @Parameter
    protected String[] endpoints;

    private String apiName;


    private AbstractMethod mtr;
    private PackageClass cls ;

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {

        this.apiName = endpoints[0];
        System.out.println("API TO USE  1= >> "+apiName);
        this.apiName = endpoints[1];
        System.out.println("API TO USE  2= >> "+apiName);

        this.apiName = "Customer360";
        if (this.project != null) {
            this.project.addCompileSourceRoot(this.outputJavaDirectory.getAbsolutePath());
            this.project.addCompileSourceRoot(this.outputJavaDirectory2.getAbsolutePath());
        }

        /*if (!this.outputJavaDirectory.mkdirs()) {
            getLog().error("Could not create source directory!");
        } else {

        }*/
        try {
            generateJavaCode();
        } catch (IOException e) {
            throw new MojoExecutionException("Could not generate Java source code!", e);
        }

        /*if (!this.outputJavaDirectory2.mkdirs()) {
            getLog().error("Could not create source directory!");
        } else {

        } */

        try {
            generateJavaCode2();
        } catch (IOException e) {
            throw new MojoExecutionException("Could not generate Java source code!", e);
        }


    }

    private void generateJavaCode2() throws IOException {
        System.setProperty("jenesis.encoder", JenesisJalopyEncoder.class.getName());
        // Get the VirtualMachine implementation.
        VirtualMachine vm = VirtualMachine.getVirtualMachine();

        // Instantiate a new CompilationUnit. The argument to the
        // compilation unit is the "codebase" or directory where the
        // compilation unit should be written.

        // Make a new compilation unit rooted to the given sourcepath.
        CompilationUnit unit = vm.newCompilationUnit(this.outputJavaDirectory2.getAbsolutePath());

        // Set the package namespace.
        unit.setNamespace("com.cs.frontline.apiimplementations");

        unit.addImport("javax.inject.Inject");
        unit.addImport("javax.ws.rs.core.Context");
        unit.addImport("javax.ws.rs.core.HttpHeaders");
        unit.addImport("javax.ws.rs.core.Response");
        unit.addImport("javax.ws.rs.core.UriInfo");
        unit.addImport("org.springframework.context.annotation.Scope");
        unit.addImport("org.springframework.stereotype.Component");
        unit.addImport(String.format("com.cs.frontoffice.api.%s",apiName));
        unit.addImport("com.cs.frontoffice.dataorchestrationengine.EndPointHandler");
        unit.addImport("reactor.core.publisher.Mono");

        PackageClass cls = unit.newPublicClass(String.format("%sImpl",apiName));
        cls.addImplements(String.format("%s",apiName));
        unit.setComment(Comment.D, "The API Implementation class.");
        cls.newField(vm.newType("EndPointHandler"),"endPointHandler").addAnnotation("Inject");

        //READ FROM JSON FILE
        JSONParser parser = new JSONParser();
        JSONObject jsonObject;
        JSONArray jsonArray;
        try{
            // parsing file
            File file = new File(String.format("src/main/resources/%s.json",apiName));
            jsonArray = (JSONArray) parser.parse(new FileReader(file));

            for(Object obj: jsonArray){
                JSONObject apiObj = (JSONObject) obj;

                String operationId = (String) apiObj.get("operationId");
                String method = (String) apiObj.get("method");
                String endPointFunction = (String) apiObj.get("endPointFunction");

                ClassMethod mtr = cls.newMethod(vm.newType("Mono<Response>"),operationId);
                mtr.setAccess(Access.PUBLIC);

                if(method == "POST" || method == "PUT"){
                    mtr.addParameter(vm.newType("String"),"requestBodyStr");
                }

                ClassType clsType = vm.newType("@Context HttpHeaders");
                ClassType clsType2 = vm.newType("@Context UriInfo");

                mtr.addParameter(clsType,"httpHeaders");
                mtr.addParameter(clsType2,"uriInfo");

                mtr.addAnnotation("Override");

                Try tr = mtr.newTry();
                tr.newCatch(vm.newType("Exception"),"e");

                Let letx = tr.newLet(vm.newType("Mono<Response>"));

                if(method.equals("GET")){
                    letx.addAssign("responseMap",vm.newInvoke("endPointHandler",String.format("%s",endPointFunction))
                            .addArg(vm.newVar("new Object() {}.getClass().getEnclosingMethod().getName()"))
                            .addArg(vm.newNull())
                            .addVarriableArg("uriInfo")
                            .addVarriableArg("httpHeaders"));

                } else {

                    letx.addAssign("responseMap",vm.newInvoke("endPointHandler","getEndpointResponse")
                            .addArg(vm.newVar("new Object() {}.getClass().getEnclosingMethod().getName()"))
                            .addArg(vm.newVar("new JSONObject(requestBodyStr)"))
                            .addVarriableArg("uriInfo")
                            .addVarriableArg("httpHeaders"));

                }

                tr.newReturn().setExpression(vm.newVar("responseMap"));

                mtr.newReturn().setExpression(vm.newNull());



            }
        } catch (Exception e){
            System.out.println("File FAILED ======");
            System.out.println(e);
        }



        unit.encode();



    }

    private void generateJavaCode() throws IOException {
        System.setProperty("jenesis.encoder", JenesisJalopyEncoder.class.getName());

        // Get the VirtualMachine implementation.
        VirtualMachine vm = VirtualMachine.getVirtualMachine();

        // Instantiate a new CompilationUnit. The argument to the
        // compilation unit is the "codebase" or directory where the
        // compilation unit should be written.
        //
        // Make a new compilation unit rooted to the given sourcepath.
        CompilationUnit unit = vm.newCompilationUnit(this.outputJavaDirectory.getAbsolutePath());

        // Set the package namespace.
        unit.setNamespace("com.cs.frontoffice.api");

        // Add an import statement for fun.
        unit.addImport("java.io.Serializable");
        unit.addImport("javax.ws.rs.GET");
        unit.addImport("javax.ws.rs.Path");
        unit.addImport("javax.ws.rs.Produces");
        unit.addImport("javax.ws.rs.core.*");
        unit.addImport("reactor.core.publisher.Mono");

        // Comment the package with a javadoc (DocumentationComment).
        unit.setComment(Comment.D, "Auto-Generated using the Jenesis Syntax API");


        // Make a new interface.
        Interface itr = unit.newPublicInterface(String.format("%s",apiName));
        itr.addAnnotation("Path").addAnntationAttribute("value").setValue(vm.newString("/"));

        // Comment the class with a javadoc (DocumentationComment).
        unit.setComment(Comment.D, String.format("%s interface.",apiName));
        ClassType t = vm.newType("Mono<Response>");


        //READ FROM JSON FILE
        JSONParser parser = new JSONParser();
        JSONObject jsonObject;
        JSONArray jsonArray;
        try{
            // parsing file
            File file = new File(String.format("src/main/resources/%s.json",apiName));
            jsonArray = (JSONArray) parser.parse(new FileReader(file));

            for(Object obj: jsonArray){
                JSONObject apiObj = (JSONObject) obj;

                String operationId = (String) apiObj.get("operationId");
                String path = (String) apiObj.get("path");
                String method = (String) apiObj.get("method");

                AbstractMethod mtr = itr.newMethod(vm.newType("Mono<Response>"),operationId);
                mtr.addAnnotation(String.format("%s",method));
                mtr.addAnnotation("Path").addAnntationAttribute("value").setValue(vm.newString(String.format("%s",path)));
                mtr.addAnnotation("Produces").addAnntationAttribute("value").setValue(vm.newString("application/json"));

                if(method.equals("POST") || method.equals("PUT")){
                    mtr.addParameter(vm.newType("@RequestBody String"),"requestBodyStr");
                }
                ClassType clsType = vm.newType("@Context HttpHeaders");
                System.out.println(clsType.getName());


                ClassType clsType2 = vm.newType("@Context UriInfo");
                System.out.println(clsType.getName());

                mtr.addParameter(clsType,"httpHeaders");
                mtr.addParameter(clsType2,"uriInfo");

                //Print interface
                System.out.println(mtr);

            }
        } catch (Exception e){
            System.out.println("File FAILED ======");
            System.out.println(e);
        }


        // Write the java file.
        unit.encode();

    }
}

If you can represent your generated code in the Mojo as a String, you can easily edit it with Spoon.如果您可以将 Mojo 中生成的代码表示为字符串,则可以使用 Spoon 轻松编辑它。 Let's say your generated code is in the String generatedCode , then the following will add an abstract method to it:假设您生成的代码在 String generatedCode中,那么以下将为它添加一个抽象方法:

// create a Spoon model of the generated code
Launcher launcher = new Launcher();
VirtualFile virtualFile = new VirtualFile(generatedCode);
launcher.addInputResource(virtualFile);
launcher.buildModel();
CtInterface ctInterface = launcher.getModel().getRootPackage().getType("Customer360");

// create an abstract method
String codeWithAbstractMethod = "package pkg; abstract class AbstractClass { abstract void abstractMethod();} ";
CtClass<?> classWithAbstractMethod = Launcher.parseClass(codeWithAbstractMethod);
CtMethod abstractMethod = classWithAbstractMethod.getMethodsByName("abstractMethod").get(0);

// add abstract method to the generated code
ctInterface.addMethod(abstractMethod);
String prettyPrint = ctInterface.toString();

prettyPrint will hold a String representation of the transformed generated code. prettyPrint将保存转换后的生成代码的字符串表示形式。 The abstract method here is only an example, Spoon has many useful tools for creating complex code elements which you can find in the documentation .这里的抽象方法只是一个例子,Spoon 有许多有用的工具来创建复杂的代码元素,您可以在文档中找到这些工具。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM