I have an interface and class file auto-generated using a custom maven plugin I created. The plugin will read the necessary data from a JSON file and create me a Java files using Jenesis4Java (Mojo code provided below).
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? 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 refers to java file in maven plugin creation process)
Mojo file for reference-
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. Let's say your generated code is in the String
generatedCode
, then the following will add an abstract method to it:prettyPrint
will hold a String representation of the transformed generated code. 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.