
net.anthavio.httl.util.JavaCodeGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hatatitla Show documentation
Show all versions of hatatitla Show documentation
Compact but tweakable REST client library you have been dreaming of
The newest version!
package net.anthavio.httl.util;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Stack;
import javax.tools.SimpleJavaFileObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Base class for java generators. Subclass should implement parse method that generate AST
*
* @author martin.vanek
*
*/
public abstract class JavaCodeGenerator {
protected final Logger logger = LoggerFactory.getLogger(getClass());
protected Stack stack = new Stack();
//declare classes as global or keep them inner (local)
protected boolean doGlobalTypes = false;
//finished custom objects - for global style declarations
protected List globals = new ArrayList();
//base class to extend
protected String baseClass;
//interfaces to implement
protected List interfaces;
protected String targetPackage;
protected DateFormat dateFormat;
public DateFormat getDateFormat() {
return dateFormat;
}
public void setDateFormat(DateFormat dateFormat) {
this.dateFormat = dateFormat;
}
public void setDateFormat(String pattern) {
this.dateFormat = new SimpleDateFormat(pattern);
}
/**
* @param className if qualified, then package par will be aslo used
* @param reader source of JSON
* @return java code
*/
public String process(String className, Reader reader) throws IOException {
if (Cutils.isEmpty(className)) {
throw new IllegalArgumentException("rootName is empty");
}
int dotIdx = className.lastIndexOf('.');
if (dotIdx != -1) {
targetPackage = className.substring(0, dotIdx);
className = className.substring(dotIdx + 1);
}
AstNode root = parse(className, reader);
//System.out.println(root);
StringWriter sw = new StringWriter();
write(root, sw);
return sw.toString();
}
public abstract AstNode parse(String className, Reader reader) throws IOException;
protected String buildFieldName(String name) {
char c0 = name.charAt(0);
if (Character.isDigit(c0)) { //OK in JSON, NOT in Java
name = "f" + name;
} else if (Character.isUpperCase(c0)) {
if (name.length() == 1) {
name = Character.toLowerCase(c0) + "";
} else {
name = Character.toLowerCase(c0) + name.substring(1);
}
}
return name;
}
protected String buildClassName(String name) {
char c0 = name.charAt(0);
if (Character.isDigit(c0)) {
name = "C" + name;
} else if (Character.isLowerCase(c0)) {
if (name.length() == 1) {
name = Character.toUpperCase(c0) + "";
} else {
name = Character.toUpperCase(c0) + name.substring(1);
}
}
return name;
}
private String buildFieldType(AstNode field) {
StringBuilder sb = new StringBuilder();
AstNode f = field;
while (f.isArray()) { //nested arrays...
sb.append("java.util.List<");
if (f.getElements().isEmpty()) {
break; //empty array
}
f = f.getElements().get(0);
}
sb.append(field.getTypeName());
f = field;
while (f.isArray()) {
sb.append(">");
if (f.getElements().isEmpty()) {
break; //empty array
}
f = f.getElements().get(0);
}
return sb.toString();
}
public void write(AstNode root, Writer writer) {
IndentingWriter w = new IndentingWriter(writer);
if (Cutils.isNotEmpty(targetPackage)) {
w.println("package " + targetPackage + ";");
}
//pw.println("import java.util.List;");
//pw.println("import java.util.Map;");
//pw.println("import java.util.Date;");
w.println("/**");
w.println(" * Generated by Hatatitla at " + new SimpleDateFormat("yyyy.MM.dd HH:mm:ss").format(new Date()));
w.println(" */");
if (root.isArray()) {
if (root.getTypeName().equals("java.util.Map")) {
//heretogenous array - elements has different types
List elements = root.getElements();
for (AstNode element : elements) {
writeClass(element, Modifier.PUBLIC, w);
}
} else {
//homogenous array - type is same so just first
writeClass(root.getElements().get(0), Modifier.PUBLIC, w);
}
} else {
writeClass(root, Modifier.PUBLIC, w);
}
for (AstNode global : globals) {
writeClass(global, 0, w);
}
}
private void writeClass(AstNode node, int modifiers, IndentingWriter w) {
if (Modifier.isPublic(modifiers)) {
w.print("public ");
} else if (Modifier.isProtected(modifiers)) {
w.print("protected ");
} else if (Modifier.isProtected(modifiers)) {
w.print("private ");
}
if (Modifier.isStatic(modifiers)) {
w.print("static ");
}
if (Modifier.isFinal(modifiers)) {
w.print("final ");
}
w.print("class " + node.getTypeName());
if (Cutils.isNotEmpty(baseClass)) {
w.print(" extends " + baseClass);
}
if (interfaces != null && interfaces.size() != 0) {
w.print(" implements ");
for (int i = 0; i < interfaces.size(); ++i) {
String itf = interfaces.get(i);
w.print(itf);
if (i < interfaces.size() - 1) {
w.print(", ");
}
}
}
w.print(" {");
w.println();
w.incLevel();
List fields = node.getElements();
for (AstNode field : fields) {
writeFieldDeclaration(w, field);
}
for (AstNode field : fields) {
writeFieldGetSet(w, field);
}
//local types
for (AstNode local : node.locals) {
writeClass(local, Modifier.PUBLIC | Modifier.STATIC, w);
}
w.decLevel();
w.println("}");
}
private void writeFieldGetSet(IndentingWriter w, AstNode field) {
String type = buildFieldType(field);
String fieldName = buildFieldName(field.getName());
String name;
if (fieldName.length() == 1) {
name = Character.toUpperCase(fieldName.charAt(0)) + "";
} else {
name = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
}
//getter
w.print("public ");
w.print(type);
w.print(" get" + name + "() {");
w.incLevel();
w.println();
w.println("return this." + fieldName + ";");
w.decLevel();
w.println("}");
//setter
w.print("public void ");
w.print(" set" + name + "(" + type + " " + fieldName + ") {");
w.incLevel();
w.println();
w.println("this." + fieldName + " = " + fieldName + ";");
w.decLevel();
w.println("}");
}
private void writeFieldDeclaration(IndentingWriter w, AstNode field) {
String type = buildFieldType(field);
String name = buildFieldName(field.getName());
w.print("private " + type + " " + name + ";");
w.println();
}
public boolean isDoGlobalTypes() {
return doGlobalTypes;
}
public void setDoGlobalTypes(boolean doGlobalTypes) {
this.doGlobalTypes = doGlobalTypes;
}
public String getBaseClass() {
return baseClass;
}
public void setBaseClass(Class> clazz) {
this.baseClass = clazz.getName();
}
public void setBaseClass(String className) {
this.baseClass = className;
}
public List getInterfaces() {
return interfaces;
}
public void setInterfaces(List> interfaces) {
this.interfaces = new ArrayList();
for (Class> clazz : interfaces) {
this.interfaces.add(clazz.getName());
}
}
public void addInterface(Class> interfacex) {
addInterface(interfacex.getName());
}
public void addInterface(String interfaceName) {
if (this.interfaces == null) {
this.interfaces = new ArrayList();
}
//disallow duplicities
if (this.interfaces.indexOf(interfaceName) == -1) {
this.interfaces.add(interfaceName);
}
}
public String getTargetPackage() {
return targetPackage;
}
public void setTargetPackage(String targetPackage) {
this.targetPackage = targetPackage;
}
}
class AstNode {
//localy declared types
public List locals = new ArrayList();
private final String name;
private final List fielems = new ArrayList(); //fields for Class, elements for Array
private String typeName;
private final boolean array;
private boolean simpleType;
public AstNode(String name, Class> clazz, boolean array) {
if (Cutils.isEmpty(name)) {
throw new IllegalArgumentException("Name is empty");
}
this.name = name;
if (clazz != null) {
setTypeName(clazz);
}
this.array = array;
}
public AstNode(String name, String typeName, boolean array) {
if (Cutils.isEmpty(name)) {
throw new IllegalArgumentException("Name is empty");
}
this.name = name;
setTypeName(typeName);
this.array = array;
}
public String getName() {
return name;
}
public String getTypeName() {
return typeName;
}
public boolean isSimpleType() {
return simpleType;
}
//For Array
public void setTypeName(Class> clazz) {
String name = clazz.getName();
if (name.startsWith("java.lang")) {
setTypeName(clazz.getSimpleName());
} else {
setTypeName(clazz.getName());
}
}
//For Object (custom)
public void setTypeName(String name) {
this.typeName = name;
if (name.startsWith("java.lang")) {
this.simpleType = true;
} else {
this.simpleType = false;
}
}
//Fields (Object) or Elements (Array)
public List getElements() {
return fielems;
}
public AstNode addField(String name, Class> type) {
if (Cutils.isEmpty(name)) {
throw new IllegalArgumentException("Name is empty");
}
AstNode node = new AstNode(name, type, false);
fielems.add(node);
return node;
}
public void addField(AstNode entry) {
fielems.add(entry);
}
public boolean isArray() {
return array;
}
@Override
public String toString() {
return "{name=" + name + ", typeName=" + typeName + ", list=" + array + ", fields=" + fielems + "}";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((fielems == null) ? 0 : fielems.hashCode());
result = prime * result + (array ? 1231 : 1237);
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((typeName == null) ? 0 : typeName.hashCode());
return result;
}
public boolean equalsFields(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AstNode other = (AstNode) obj;
if (array != other.array)
return false;
if (fielems == null) {
if (other.fielems != null)
return false;
} else if (!array) {
if (simpleType) { //when simple - type must be same
if (typeName == null) {
if (other.typeName != null)
return false;
} else if (!typeName.equals(other.typeName))
return false;
} else { //when class - field must be precisely the same
if (!fielems.equals(other.fielems))
return false;
}
} else if (array) { //when array - only type of fields must by same
//we will determine field's type by own type
if (typeName == null) {
if (other.typeName != null)
return false;
} else if (!typeName.equals(other.typeName))
return false;
}
/*
if (typeName == null) {
if (other.typeName != null)
return false;
} else if (!typeName.equals(other.typeName))
return false;
*/
return true;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AstNode other = (AstNode) obj;
if (fielems == null) {
if (other.fielems != null)
return false;
} else if (!fielems.equals(other.fielems))
return false;
if (array != other.array)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (typeName == null) {
if (other.typeName != null)
return false;
} else if (!typeName.equals(other.typeName))
return false;
return true;
}
}
class Clazz {
private final Class> clazz;
private final String name;
/**
* Custom class
*/
public Clazz(String name) {
this.name = name;
this.clazz = null;
}
/**
* String/Integer/Date
*/
public Clazz(Class> clazz) {
if (clazz == null) {
throw new IllegalArgumentException("null clazz");
}
this.clazz = clazz;
this.name = null;
}
public String getName() {
if (clazz != null) {
String name = clazz.getName();
if (name.startsWith("java.lang")) {
return clazz.getSimpleName();
} else {
return clazz.getName();
}
} else {
return name;
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((clazz == null) ? 0 : clazz.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Clazz other = (Clazz) obj;
if (clazz == null) {
if (other.clazz != null)
return false;
} else if (!clazz.equals(other.clazz))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Clazz [clazz=" + clazz + ", name=" + name + "]";
}
}
class IndentingWriter {
private String token = "\t";
private int level = 0;
private final PrintWriter pw;
private boolean newline;
public IndentingWriter(OutputStream stream) {
this.pw = new PrintWriter(stream);
}
public IndentingWriter(Writer writer) {
this.pw = new PrintWriter(writer);
}
public int incLevel() {
return ++level;
}
public int decLevel() {
return --level;
}
public void print(Object object) {
if (newline) {
for (int i = 0; i < level; ++i) {
pw.print(token);
}
newline = false;
}
pw.print(object);
}
public void println() {
pw.println();
this.newline = true;
}
public void println(Object object) {
print(object);
pw.println();
this.newline = true;
}
public void close() {
pw.close();
}
}
class StringJavaObject extends SimpleJavaFileObject {
private String contents = null;
public StringJavaObject(String className, String classCode) {
super(URI.create(className), Kind.SOURCE);
this.contents = classCode;
}
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return contents;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy