Using JET to generate code: indentation

I am trying to do the following:

Write a JET template that receives an object of type Class as argument. The object must be a Java interface. The template generates a class that implements the interface, i.e. provides methods for all method signatures that it defines. The name of the generated class should be XImplementation, where X is the interface argument name. Methods in the generated class do nothing or only return constants: 0 for int and double, false for boolean and null for reference types. You do not need to consider any other return types. For instance. for the following interface A, an implementation of the AI ​​class is generated:

interface A { void m1(int x, int y); int m2(Object a); Object m3(); } class AImplementation implements A { public void m1(int p1, int p2) { } public int m2(Object p1) { return 0; } public Object m3() { return null; } } 

Hint: An unqualified (simple) type name can be obtained using the getSimpleName () method on the corresponding class object.

I read the JET tutorials found on eclipse.org, but it's still hard for me to figure out what I need to do.

When I make a .txtjet file for translation, do I try to make the implementation of the .txtjet file write a huge line of code that I want to generate in the generate method? Is this the right concept?

If so, I am having problems with one particular aspect. This is the JET template that I have provided so far:

 <%@ jet imports="java.lang.reflect.*" class="Q2Generator" %> <%Object o = (Object) argument;%> <%Class c = o.getClass();%> public class <%=c.getName()%>Implementation implements <%=c.getName()%> { <%for (Method m : c.getDeclaredMethods()) {%> <% Class type = m.getReturnType();%> <% if (!type.isPrimitive()) {%> public <%=type.getSimpleName()%> <%=m.getName()%> { return null; } // this line is the problem <% }%> <%}%> } 

This template leads to the following code in the generate method:

  public final String NL = nl == null ? (System.getProperties().getProperty("line.separator")) : nl; protected final String TEXT_1 = NL + "public class "; protected final String TEXT_2 = "Implementation implements "; protected final String TEXT_3 = " {"; protected final String TEXT_4 = NL + "public "; protected final String TEXT_5 = " "; protected final String TEXT_6 = " { return null; }"; protected final String TEXT_7 = NL + "\t\t" + NL + "}"; protected final String TEXT_8 = NL; public String generate(Object argument) { final StringBuffer stringBuffer = new StringBuffer(); Object o = (Object) argument; Class c = o.getClass(); stringBuffer.append(TEXT_1); stringBuffer.append(c.getName()); stringBuffer.append(TEXT_2); stringBuffer.append(c.getName()); stringBuffer.append(TEXT_3); for (Method m : c.getDeclaredMethods()) { Class type = m.getReturnType(); if (!type.isPrimitive()) { stringBuffer.append(TEXT_4); stringBuffer.append(type.getSimpleName()); stringBuffer.append(TEXT_5); stringBuffer.append(m.getName()); stringBuffer.append(TEXT_6); } } stringBuffer.append(TEXT_7); stringBuffer.append(TEXT_8); return stringBuffer.toString(); } 

Is there a way to stringBuffer.append() in an if statement? And is String the right way to solve this?

Thanks.

+4
source share
1 answer

I would use the new JET2 syntax. You must create a new JET transform using New -> Other.

As for what happens at a high level, you will have a template named main.jet that will act as a controller. It does not create any textual content, but it will manage the generation of projects, folders and files.

I understand that you want to use the class object as input, but I recommend that you create your own templates for using an XML file as input. Something like that:

 <root> <object name="A"> <method name="m1" returns="void"> <arg name="x" type="int" /> <arg name="y" type="int" /> </method> <method name="m2" returns="int"> <arg name="a" type="Object" /> </method> <method name="m3" returns="Object"> </method> </object> </root> 

You can see that given the class, we can "easily" create such an XML document.

So main.jet will look something like this:

 <%@taglib prefix="ws" id="org.eclipse.jet.workspaceTags" %> <c:iterate select="/root/object" var="object" <c:set select="$object" name="impl" ><c:get select="$object/@name"/>Implementation</c:set> <c:set select="$object" name="interface" ><c:get select="$object/@name"/></c:set> </c:iterate> <c:iterate select="/root/object" var="object"> <ws:file path="my project/src/a/b/c/{$object/@interface}.java" template="interface.jet" /> <ws:file path="my project/src/a/b/c/{$object/@impl}.java" template="impl.jet" /> </c:iterate> 

Basically, you iterate over each object (you can define as many as you want), and you build the implementation and interface names and save those names back to the model.
After you have completed all the naming conventions, you iterate over the elements of the object and apply the templates to the model using the ws: file tag. The tag indicates which template to use, and then indicates the file name to create with the generation results.

The interface.jet file might look something like this:

 package abc; interface <c:get select="$object/@interface"/> { <c:iterate select="$object/method" var="method" > <c:get select="$method/@returns"/> <c:get select="$method/@name"/>(int x, int y); </c:iterate> } 

Please note that I hardcoded the package as abc. You can make this variable by adding an attribute to the XML file, possibly to the element of the object and using the c: get tag to paste it into the source code. I also left the arguments hardcoded, but you can use another iterate tag to iterate over the nested elements of the model to record the method signature.

So, I will dwell on this to make sure that this is what you were looking for. You can ask more comments or ask more questions.

0
source

All Articles