/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.fusesource.hawtbuf.proto.compiler; import static org.fusesource.hawtbuf.proto.WireFormat.WIRETYPE_FIXED32; import static org.fusesource.hawtbuf.proto.WireFormat.WIRETYPE_FIXED64; import static org.fusesource.hawtbuf.proto.WireFormat.WIRETYPE_LENGTH_DELIMITED; import static org.fusesource.hawtbuf.proto.WireFormat.WIRETYPE_VARINT; import static org.fusesource.hawtbuf.proto.WireFormat.makeTag; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; import java.util.StringTokenizer; import org.fusesource.hawtbuf.proto.compiler.parser.ParseException; import org.fusesource.hawtbuf.proto.compiler.parser.ProtoParser; public class AltJavaGenerator { private File out = new File("."); private File[] path = new File[]{new File(".")}; private ProtoDescriptor proto; private String javaPackage; private String outerClassName; private PrintWriter w; private int indent; private ArrayList<String> errors = new ArrayList<String>(); private boolean multipleFiles; private boolean auto_clear_optional_fields; private String factoryFeild = "FACTORY"; private String getterCN = "Getter"; private String beanCN = "Bean"; private String bufferCN = "Buffer"; public static void main(String[] args) { AltJavaGenerator generator = new AltJavaGenerator(); args = CommandLineSupport.setOptions(generator, args); if (args.length == 0) { System.out.println("No proto files specified."); } for (int i = 0; i < args.length; i++) { try { System.out.println("Compiling: " + args[i]); generator.compile(new File(args[i])); } catch (CompilerException e) { System.out.println("Protocol Buffer Compiler failed with the following error(s):"); for (String error : e.getErrors()) { System.out.println(""); System.out.println(error); } System.out.println(""); System.out.println("Compile failed. For more details see error messages listed above."); return; } } } interface Closure { void execute() throws CompilerException; } public void compile(File file) throws CompilerException { // Parse the proto file FileInputStream is = null; try { is = new FileInputStream(file); ProtoParser parser = new ProtoParser(is); proto = parser.ProtoDescriptor(); proto.setName(file.getName()); loadImports(proto, file.getParentFile()); proto.validate(errors); } catch (FileNotFoundException e) { errors.add("Failed to open: " + file.getPath() + ":" + e.getMessage()); } catch (ParseException e) { errors.add("Failed to parse: " + file.getPath() + ":" + e.getMessage()); } finally { try { is.close(); } catch (Throwable ignore) { } } if (!errors.isEmpty()) { throw new CompilerException(errors); } // Load the options.. javaPackage = javaPackage(proto); outerClassName = javaClassName(proto); // optimizeFor = getOption(proto.getOptions(), "optimize_for", "SPEED"); multipleFiles = isMultipleFilesEnabled(proto); // deferredDecode = Boolean.parseBoolean(getOption(proto.getOptions(), "deferred_decode", "false")); auto_clear_optional_fields = Boolean.parseBoolean(getOption(proto.getOptions(), "auto_clear_optional_fields", "false")); if (multipleFiles) { generateProtoFile(); } else { writeFile(outerClassName, new Closure() { public void execute() throws CompilerException { generateProtoFile(); } }); } if (!errors.isEmpty()) { throw new CompilerException(errors); } } private void writeFile(String className, Closure closure) throws CompilerException { PrintWriter oldWriter = w; // Figure out the java file name.. File outputFile = out; if (javaPackage != null) { String packagePath = javaPackage.replace('.', '/'); outputFile = new File(outputFile, packagePath); } outputFile = new File(outputFile, className + ".java"); // Start writing the output file.. outputFile.getParentFile().mkdirs(); FileOutputStream fos = null; try { fos = new FileOutputStream(outputFile); w = new PrintWriter(fos); closure.execute(); w.flush(); } catch (FileNotFoundException e) { errors.add("Failed to write to: " + outputFile.getPath() + ":" + e.getMessage()); } finally { try { fos.close(); } catch (Throwable ignore) { } w = oldWriter; } } private void loadImports(ProtoDescriptor proto, File protoDir) { LinkedHashMap<String, ProtoDescriptor> children = new LinkedHashMap<String, ProtoDescriptor>(); for (String imp : proto.getImports()) { File file = new File(protoDir, imp); for (int i = 0; i < path.length && !file.exists(); i++) { file = new File(path[i], imp); } if (!file.exists()) { errors.add("Cannot load import: " + imp); } FileInputStream is = null; try { is = new FileInputStream(file); ProtoParser parser = new ProtoParser(is); ProtoDescriptor child = parser.ProtoDescriptor(); child.setName(file.getName()); loadImports(child, file.getParentFile()); children.put(imp, child); } catch (ParseException e) { errors.add("Failed to parse: " + file.getPath() + ":" + e.getMessage()); } catch (FileNotFoundException e) { errors.add("Failed to open: " + file.getPath() + ":" + e.getMessage()); } finally { try { is.close(); } catch (Throwable ignore) { } } } proto.setImportProtoDescriptors(children); } private void generateProtoFile() throws CompilerException { if (multipleFiles) { for (EnumDescriptor value : proto.getEnums().values()) { final EnumDescriptor o = value; String className = uCamel(o.getName()); writeFile(className, new Closure() { public void execute() throws CompilerException { generateFileHeader(); generateEnum(o); } }); } for (MessageDescriptor value : proto.getMessages().values()) { final MessageDescriptor o = value; String className = uCamel(o.getName()); writeFile(className, new Closure() { public void execute() throws CompilerException { generateFileHeader(); generateMessageBean(o); } }); } } else { generateFileHeader(); p("public class " + outerClassName + " {"); indent(); for (EnumDescriptor enumType : proto.getEnums().values()) { generateEnum(enumType); } for (MessageDescriptor m : proto.getMessages().values()) { generateMessageBean(m); } unindent(); p("}"); } } private void generateFileHeader() { p("//"); p("// Generated by protoc, do not edit by hand."); p("//"); if (javaPackage != null) { p("package " + javaPackage + ";"); p(""); } } private void generateMessageBean(MessageDescriptor m) { String type = uCamel(m.getName()); p(); String staticOption = "static "; if (multipleFiles && m.getParent() == null) { staticOption = ""; } p(staticOption + "public class " + type + " implements org.fusesource.hawtbuf.proto.PBMessageFactory<" + qualified(type, beanCN) + ", " + qualified(type, bufferCN) + "> {"); p(); indent(); for (EnumDescriptor enumType : m.getEnums().values()) { generateEnum(enumType); } // Generate the Nested Messages. for (MessageDescriptor subMessage : m.getMessages().values()) { generateMessageBean(subMessage); } // Generate the Group Messages for (FieldDescriptor field : m.getFields().values()) { if (field.isGroup()) { generateMessageBean(field.getGroup()); } } p("public static final " + type + " "+factoryFeild+" = new " + type + "();"); p("public static final org.fusesource.hawtbuf.proto.PBMessageFramedCodec<"+bufferCN+"> FRAMED_CODEC = new org.fusesource.hawtbuf.proto.PBMessageFramedCodec<"+bufferCN+">("+factoryFeild+");"); p("public static final org.fusesource.hawtbuf.proto.PBMessageUnframedCodec<"+bufferCN+"> UNFRAMED_CODEC = new org.fusesource.hawtbuf.proto.PBMessageUnframedCodec<"+bufferCN+">("+factoryFeild+");"); p(); p("public " + beanCN + " create() {"); indent(); p("return new " + beanCN + "();"); unindent(); p("}"); p(); generateMethodParseFrom(m, bufferCN, beanCN); // Generate the field getters String gettrsExtendsClause = " extends org.fusesource.hawtbuf.proto.PBMessage<" + qualified(type, beanCN) + ", " + qualified(type, bufferCN) + ">"; for (EnumFieldDescriptor enumFeild : m.getAssociatedEnumFieldDescriptors()) { String name = uCamel(enumFeild.getParent().getName()); name = name + "." + name + "Creatable"; gettrsExtendsClause += ", " + name; } p(staticOption + "public interface " + getterCN + gettrsExtendsClause + " {"); p(); indent(); { for (FieldDescriptor field : m.getFields().values()) { generateFieldGetterSignatures(field); } p("public " + beanCN + " copy();"); p("public " + bufferCN + " freeze();"); p("public java.lang.StringBuilder toString(java.lang.StringBuilder sb, String prefix);"); } unindent(); p("}"); p(); p("static public final class " + beanCN + " implements " + getterCN + " {"); p(); indent(); p("" + bufferCN + " frozen;"); p("" + beanCN + " bean;"); p(); p("public " + beanCN + "() {"); indent(); p("this.bean = this;"); unindent(); p("}"); p(); p("public " + beanCN + "(" + beanCN + " copy) {"); indent(); p("this.bean = copy;"); unindent(); p("}"); p(); p("public " + beanCN + " copy() {"); indent(); p("return new " + beanCN + "(bean);"); unindent(); p("}"); p(); generateMethodFreeze(m, bufferCN); p("private void copyCheck() {"); indent(); p("assert frozen==null : org.fusesource.hawtbuf.proto.MessageBufferSupport.FORZEN_ERROR_MESSAGE;"); p("if (bean != this) {"); indent(); p("copy(bean);"); unindent(); p("}"); unindent(); p("}"); p(); generateMethodCopyFromBean(m, beanCN); // Generate the field accessors.. for (FieldDescriptor field : m.getFields().values()) { generateFieldAccessor(beanCN, field); } generateMethodToString(m); generateMethodMergeFromStream(m, beanCN); generateBeanEquals(m, beanCN); generateMethodMergeFromBean(m, getterCN, beanCN); generateMethodClear(m); generateReadWriteExternal(m); for (EnumFieldDescriptor enumFeild : m.getAssociatedEnumFieldDescriptors()) { String enumName = uCamel(enumFeild.getParent().getName()); p("public " + enumName + " to" + enumName + "() {"); indent(); p("return " + enumName + "." + enumFeild.getName() + ";"); unindent(); p("}"); p(); } unindent(); p("}"); p(); p("static public final class " + bufferCN + " implements org.fusesource.hawtbuf.proto.MessageBuffer<" + qualified(type, beanCN) + ", " + qualified(type, bufferCN) + ">, " + getterCN + " {"); p(); indent(); p("private " + beanCN + " bean;"); p("private org.fusesource.hawtbuf.Buffer buffer;"); p("private int size=-1;"); p("private int hashCode;"); p(); p("private " + bufferCN + "(org.fusesource.hawtbuf.Buffer buffer) {"); indent(); p("this.buffer = buffer;"); unindent(); p("}"); p(); p("private " + bufferCN + "(" + beanCN + " bean) {"); indent(); p("this.bean = bean;"); unindent(); p("}"); p(); p("public " + beanCN + " copy() {"); indent(); p("return bean().copy();"); unindent(); p("}"); p(); p("public " + bufferCN + " freeze() {"); indent(); p("return this;"); unindent(); p("}"); p(); p("private " + beanCN + " bean() {"); indent(); p("if (bean == null) {"); indent(); p("try {"); indent(); p("bean = new " + beanCN + "().mergeUnframed(new org.fusesource.hawtbuf.proto.CodedInputStream(buffer));"); p("bean.frozen=this;"); unindent(); p("} catch (org.fusesource.hawtbuf.proto.InvalidProtocolBufferException e) {"); indent(); p("throw new RuntimeException(e);"); unindent(); p("} catch (java.io.IOException e) {"); indent(); p("throw new RuntimeException(\"An IOException was thrown (should never happen in this method).\", e);"); unindent(); p("}"); unindent(); p("}"); p("return bean;"); unindent(); p("}"); p(); p("public String toString() {"); indent(); p("return bean().toString();"); unindent(); p("}"); p(); p("public java.lang.StringBuilder toString(java.lang.StringBuilder sb, String prefix) {"); indent(); p("return bean().toString(sb, prefix);"); unindent(); p("}"); p(); for (FieldDescriptor field : m.getFields().values()) { generateBufferGetters(field); } generateMethodWrite(m); generateMethodSerializedSize(m); generateBufferEquals(m, bufferCN); p("public boolean frozen() {"); indent(); p("return true;"); unindent(); p("}"); for (EnumFieldDescriptor enumFeild : m.getAssociatedEnumFieldDescriptors()) { String enumName = uCamel(enumFeild.getParent().getName()); p("public " + enumName + " to" + enumName + "() {"); indent(); p("return " + enumName + "." + enumFeild.getName() + ";"); unindent(); p("}"); p(); } unindent(); p("}"); p(); // generateMethodVisitor(m); // generateMethodType(m, className); unindent(); p("}"); p(); } private void generateMethodFreeze(MessageDescriptor m, String bufferClassName) { p("public boolean frozen() {"); indent(); p("return frozen!=null;"); unindent(); p("}"); p(); p("public " + bufferClassName + " freeze() {"); indent(); p("if( frozen==null ) {"); indent(); p("frozen = new " + bufferClassName + "(bean);"); p("assert deepFreeze();"); unindent(); p("}"); p("return frozen;"); unindent(); p("}"); p(); p("private boolean deepFreeze() {"); indent(); p("frozen.serializedSizeUnframed();"); p("return true;"); unindent(); p("}"); p(); } private boolean isPrimitive(String type) { return type.equals("int") || type.equals("long") || type.equals("double") || type.equals("float") || type.equals("boolean"); } private boolean isBuferOrString(String type) { return type.equals("org.fusesource.hawtbuf.AsciiBuffer") || type.equals("org.fusesource.hawtbuf.UTF8Buffer") || type.equals("org.fusesource.hawtbuf.Buffer") || type.equals("java.lang.String"); } /** * @param m * @param className */ private void generateMethodCopyFromBean(MessageDescriptor m, String className) { p("private void copy(" + className + " other) {"); indent(); p("this.bean = this;"); for (FieldDescriptor field : m.getFields().values()) { String lname = lCamel(field.getName()); String type = field.getRule() == FieldDescriptor.REPEATED_RULE ? javaCollectionType(field) : javaType(field); boolean primitive = isPrimitive(javaType(field)); if (field.isRepeated()) { if (primitive || isBuferOrString(type) || field.getTypeDescriptor().isEnum()) { p("this.f_" + lname + " = other.f_" + lname + ";"); p("if( this.f_" + lname + " !=null && !other.frozen()) {"); indent(); p("this.f_" + lname + " = new java.util.ArrayList<" + type + ">(this.f_" + lname + ");"); unindent(); p("}"); } else { p("this.f_" + lname + " = other.f_" + lname + ";"); p("if( this.f_" + lname + " !=null) {"); indent(); p("this.f_" + lname + " = new java.util.ArrayList<" + type + ">(other.f_" + lname + ".size());"); p("for( " + type + " e : other.f_" + lname + ") {"); indent(); p("this.f_" + lname + ".add(e.copy());"); unindent(); p("}"); unindent(); p("}"); } } else { if (primitive || isBuferOrString(type) || field.getTypeDescriptor().isEnum()) { p("this.f_" + lname + " = other.f_" + lname + ";"); if (primitive) { p("this.b_" + lname + " = other.b_" + lname + ";"); } } else { p("this.f_" + lname + " = other.f_" + lname + ";"); p("if( this.f_" + lname + " !=null ) {"); indent(); p("this.f_" + lname + " = this.f_" + lname + ".copy();"); unindent(); p("}"); } } } unindent(); p("}"); p(); } /** * If the java_visitor message option is set, then this method generates a visitor method. The option * speifiies the class name of the visitor and optionally the return value and exceptions thrown by the visitor. * <p/> * Examples: * <p/> * option java_visitor = "org.apache.kahadb.store.Visitor"; * generates: * public void visit(org.apache.kahadb.store.Visitor visitor) { * visitor.visit(this); * } * <p/> * option java_visitor = "org.apache.kahadb.store.Visitor:int:java.io.IOException"; * generates: * public int visit(org.apache.kahadb.store.Visitor visitor) throws java.io.IOException { * return visitor.visit(this); * } * * @param m */ private void generateMethodVisitor(MessageDescriptor m) { String javaVisitor = getOption(m.getOptions(), "java_visitor", null); if (javaVisitor != null) { String returns = "void"; String throwsException = null; StringTokenizer st = new StringTokenizer(javaVisitor, ":"); String vistorClass = st.nextToken(); if (st.hasMoreTokens()) { returns = st.nextToken(); } if (st.hasMoreTokens()) { throwsException = st.nextToken(); } String throwsClause = ""; if (throwsException != null) { throwsClause = "throws " + throwsException + " "; } p("public " + returns + " visit(" + vistorClass + " visitor) " + throwsClause + "{"); indent(); if ("void".equals(returns)) { p("visitor.visit(this);"); } else { p("return visitor.visit(this);"); } unindent(); p("}"); p(); } } private void generateMethodType(MessageDescriptor m, String className) { String typeEnum = getOption(m.getOptions(), "java_type_method", null); if (typeEnum != null) { TypeDescriptor typeDescriptor = m.getType(typeEnum); if (typeDescriptor == null) { typeDescriptor = m.getProtoDescriptor().getType(typeEnum); } if (typeDescriptor == null || !typeDescriptor.isEnum()) { errors.add("The java_type_method option on the " + m.getName() + " message does not point to valid enum type"); return; } String constant = constantCase(className); EnumDescriptor enumDescriptor = (EnumDescriptor) typeDescriptor; if (enumDescriptor.getFields().get(constant) == null) { errors.add("The java_type_method option on the " + m.getName() + " message does not points to the " + typeEnum + " enum but it does not have an entry for " + constant); } String type = qualified(javaFactoryType(typeDescriptor), getterCN); p("public " + type + " type() {"); indent(); p("return " + type + "." + constant + ";"); unindent(); p("}"); p(); } } private void generateMethodParseFrom(MessageDescriptor m, String bufferClassName, String beanClassName) { p("public " + beanClassName + " parseUnframed(org.fusesource.hawtbuf.proto.CodedInputStream data) throws org.fusesource.hawtbuf.proto.InvalidProtocolBufferException, java.io.IOException {"); indent(); p("return new " + beanClassName + "().mergeUnframed(data);"); unindent(); p("}"); p(); p("public " + beanClassName + " parseUnframed(java.io.InputStream data) throws org.fusesource.hawtbuf.proto.InvalidProtocolBufferException, java.io.IOException {"); indent(); p("return parseUnframed(new org.fusesource.hawtbuf.proto.CodedInputStream(data));"); unindent(); p("}"); p(); p("public " + bufferClassName + " parseUnframed(org.fusesource.hawtbuf.Buffer data) throws org.fusesource.hawtbuf.proto.InvalidProtocolBufferException {"); indent(); p("return new " + bufferClassName + "(data);"); unindent(); p("}"); p(); p("public " + bufferClassName + " parseUnframed(byte[] data) throws org.fusesource.hawtbuf.proto.InvalidProtocolBufferException {"); indent(); p("return parseUnframed(new org.fusesource.hawtbuf.Buffer(data));"); unindent(); p("}"); p(); p("public " + bufferClassName + " parseFramed(org.fusesource.hawtbuf.proto.CodedInputStream data) throws org.fusesource.hawtbuf.proto.InvalidProtocolBufferException, java.io.IOException {"); indent(); p("int length = data.readRawVarint32();"); p("int oldLimit = data.pushLimit(length);"); p("" + bufferClassName + " rc = parseUnframed(data.readRawBytes(length));"); p("data.popLimit(oldLimit);"); p("return rc;"); unindent(); p("}"); p(); p("public " + bufferClassName + " parseFramed(org.fusesource.hawtbuf.Buffer data) throws org.fusesource.hawtbuf.proto.InvalidProtocolBufferException {"); indent(); p("try {"); indent(); p("org.fusesource.hawtbuf.proto.CodedInputStream input = new org.fusesource.hawtbuf.proto.CodedInputStream(data);"); p("" + bufferClassName + " rc = parseFramed(input);"); p("input.checkLastTagWas(0);"); p("return rc;"); unindent(); p("} catch (org.fusesource.hawtbuf.proto.InvalidProtocolBufferException e) {"); indent(); p("throw e;"); unindent(); p("} catch (java.io.IOException e) {"); indent(); p("throw new RuntimeException(\"An IOException was thrown (should never happen in this method).\", e);"); unindent(); p("}"); unindent(); p("}"); p(); p("public " + bufferClassName + " parseFramed(byte[] data) throws org.fusesource.hawtbuf.proto.InvalidProtocolBufferException {"); indent(); p("return parseFramed(new org.fusesource.hawtbuf.Buffer(data));"); unindent(); p("}"); p(); p("public " + bufferClassName + " parseFramed(java.io.InputStream data) throws org.fusesource.hawtbuf.proto.InvalidProtocolBufferException, java.io.IOException {"); indent(); p("return parseUnframed(org.fusesource.hawtbuf.proto.MessageBufferSupport.readFrame(data));"); unindent(); p("}"); p(); } private void generateBeanEquals(MessageDescriptor m, String className) { p("public boolean equals(Object obj) {"); indent(); p("if( obj==this )"); p(" return true;"); p(""); p("if( obj==null || obj.getClass()!=" + className + ".class )"); p(" return false;"); p(""); p("return equals((" + className + ")obj);"); unindent(); p("}"); p(""); p("public boolean equals(" + className + " obj) {"); indent(); for (FieldDescriptor field : m.getFields().values()) { String uname = uCamel(field.getName()); String getterMethod = "get" + uname + "()"; String hasMethod = "has" + uname + "()"; if (field.getRule() == FieldDescriptor.REPEATED_RULE) { getterMethod = "get" + uname + "List()"; } p("if (" + hasMethod + " ^ obj." + hasMethod + " ) "); p(" return false;"); if (field.getRule() != FieldDescriptor.REPEATED_RULE && (field.isNumberType() || field.getType() == FieldDescriptor.BOOL_TYPE)) { p("if (" + hasMethod + " && ( " + getterMethod + "!=obj." + getterMethod + " ))"); } else { p("if (" + hasMethod + " && ( !" + getterMethod + ".equals(obj." + getterMethod + ") ))"); } p(" return false;"); } p("return true;"); unindent(); p("}"); p(""); p("public int hashCode() {"); indent(); int hc = className.hashCode(); p("int rc=" + hc + ";"); int counter = 0; for (FieldDescriptor field : m.getFields().values()) { counter++; String uname = uCamel(field.getName()); String getterMethod = "get" + uname + "()"; String hasMethod = "has" + uname + "()"; if (field.getRule() == FieldDescriptor.REPEATED_RULE) { getterMethod = "get" + uname + "List()"; } p("if (" + hasMethod + ") {"); indent(); if (field.getRule() == FieldDescriptor.REPEATED_RULE) { p("rc ^= ( " + uname.hashCode() + "^" + getterMethod + ".hashCode() );"); } else if (field.isInteger32Type()) { p("rc ^= ( " + uname.hashCode() + "^" + getterMethod + " );"); } else if (field.isInteger64Type()) { p("rc ^= ( " + uname.hashCode() + "^(new Long(" + getterMethod + ")).hashCode() );"); } else if (field.getType() == FieldDescriptor.DOUBLE_TYPE) { p("rc ^= ( " + uname.hashCode() + "^(new Double(" + getterMethod + ")).hashCode() );"); } else if (field.getType() == FieldDescriptor.FLOAT_TYPE) { p("rc ^= ( " + uname.hashCode() + "^(new Double(" + getterMethod + ")).hashCode() );"); } else if (field.getType() == FieldDescriptor.BOOL_TYPE) { p("rc ^= ( " + uname.hashCode() + "^ (" + getterMethod + "? " + counter + ":-" + counter + ") );"); } else { p("rc ^= ( " + uname.hashCode() + "^" + getterMethod + ".hashCode() );"); } unindent(); p("}"); } p("return rc;"); unindent(); p("}"); p(""); } private void generateBufferEquals(MessageDescriptor m, String className) { p("public boolean equals(Object obj) {"); indent(); p("if( obj==this )"); p(" return true;"); p(""); p("if( obj==null || obj.getClass()!=" + className + ".class )"); p(" return false;"); p(""); p("return equals((" + className + ")obj);"); unindent(); p("}"); p(""); p("public boolean equals(" + className + " obj) {"); indent(); p("return toUnframedBuffer().equals(obj.toUnframedBuffer());"); unindent(); p("}"); p(""); p("public int hashCode() {"); indent(); int hc = className.hashCode(); p("if( hashCode==0 ) {"); p("hashCode=" + hc + " ^ toUnframedBuffer().hashCode();"); p("}"); p("return hashCode;"); unindent(); p("}"); p(""); } /** * @param m */ private void generateMethodSerializedSize(MessageDescriptor m) { p("public int serializedSizeFramed() {"); indent(); p("int t = serializedSizeUnframed();"); p("return org.fusesource.hawtbuf.proto.CodedOutputStream.computeRawVarint32Size(t) + t;"); unindent(); p("}"); p(); p("public int serializedSizeUnframed() {"); indent(); p("if (buffer != null) {"); indent(); p("return buffer.length;"); unindent(); p("}"); p("if (size != -1)"); p(" return size;"); p(); p("size = 0;"); for (FieldDescriptor field : m.getFields().values()) { String uname = uCamel(field.getName()); String getter = "get" + uname + "()"; String type = javaType(field); if (!field.isRequired()) { p("if (has" + uname + "()) {"); indent(); } if (field.getRule() == FieldDescriptor.REPEATED_RULE) { p("for (" + type + " i : get" + uname + "List()) {"); indent(); getter = "i"; } if (field.getType() == FieldDescriptor.STRING_TYPE) { p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeStringSize(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.BYTES_TYPE) { p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeBytesSize(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.BOOL_TYPE) { p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeBoolSize(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.DOUBLE_TYPE) { p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeDoubleSize(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.FLOAT_TYPE) { p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeFloatSize(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.INT32_TYPE) { p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeInt32Size(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.INT64_TYPE) { p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeInt64Size(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.SINT32_TYPE) { p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeSInt32Size(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.SINT64_TYPE) { p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeSInt64Size(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.UINT32_TYPE) { p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeUInt32Size(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.UINT64_TYPE) { p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeUInt64Size(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.FIXED32_TYPE) { p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeFixed32Size(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.FIXED64_TYPE) { p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeFixed64Size(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.SFIXED32_TYPE) { p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeSFixed32Size(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.SFIXED64_TYPE) { p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeSFixed64Size(" + field.getTag() + ", " + getter + ");"); } else if (field.getTypeDescriptor().isEnum()) { p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeEnumSize(" + field.getTag() + ", " + getter + ".getNumber());"); } else if (field.getGroup() != null) { errors.add("This code generator does not support group fields."); // p("size += org.fusesource.hawtbuf.proto.MessageBufferSupport.computeGroupSize("+field.getTag()+", ("+type+"Buffer)"+getter+");"); } else { p("size += org.fusesource.hawtbuf.proto.MessageBufferSupport.computeMessageSize(" + field.getTag() + ", " + getter + ".freeze());"); } if (field.getRule() == FieldDescriptor.REPEATED_RULE) { unindent(); p("}"); } if (!field.isRequired()) { unindent(); p("}"); } } // TODO: handle unknown fields // size += getUnknownFields().getSerializedSize();"); p("return size;"); unindent(); p("}"); p(); } /** * @param m */ private void generateMethodWrite(MessageDescriptor m) { p("public org.fusesource.hawtbuf.Buffer toUnframedBuffer() {"); indent(); p("if( buffer !=null ) {"); indent(); p("return buffer;"); unindent(); p("}"); p("return org.fusesource.hawtbuf.proto.MessageBufferSupport.toUnframedBuffer(this);"); unindent(); p("}"); p(); p("public org.fusesource.hawtbuf.Buffer toFramedBuffer() {"); indent(); p("return org.fusesource.hawtbuf.proto.MessageBufferSupport.toFramedBuffer(this);"); unindent(); p("}"); p(); p("public byte[] toUnframedByteArray() {"); indent(); p("return toUnframedBuffer().toByteArray();"); unindent(); p("}"); p(); p("public byte[] toFramedByteArray() {"); indent(); p("return toFramedBuffer().toByteArray();"); unindent(); p("}"); p(); p("public void writeFramed(org.fusesource.hawtbuf.proto.CodedOutputStream output) throws java.io.IOException {"); indent(); p("output.writeRawVarint32(serializedSizeUnframed());"); p("writeUnframed(output);"); unindent(); p("}"); p(); p("public void writeFramed(java.io.OutputStream output) throws java.io.IOException {"); indent(); p("org.fusesource.hawtbuf.proto.CodedOutputStream codedOutput = new org.fusesource.hawtbuf.proto.CodedOutputStream(output);"); p("writeFramed(codedOutput);"); p("codedOutput.flush();"); unindent(); p("}"); p(); p("public void writeUnframed(java.io.OutputStream output) throws java.io.IOException {"); indent(); p("org.fusesource.hawtbuf.proto.CodedOutputStream codedOutput = new org.fusesource.hawtbuf.proto.CodedOutputStream(output);"); p("writeUnframed(codedOutput);"); p("codedOutput.flush();"); unindent(); p("}"); p(); p("public void writeUnframed(org.fusesource.hawtbuf.proto.CodedOutputStream output) throws java.io.IOException {"); indent(); p("if (buffer == null) {"); indent(); p("int size = serializedSizeUnframed();"); p("buffer = output.getNextBuffer(size);"); p("org.fusesource.hawtbuf.proto.CodedOutputStream original=null;"); p("if( buffer == null ) {"); indent(); p("buffer = new org.fusesource.hawtbuf.Buffer(new byte[size]);"); p("original = output;"); p("output = new org.fusesource.hawtbuf.proto.CodedOutputStream(buffer);"); unindent(); p("}"); for (FieldDescriptor field : m.getFields().values()) { String uname = uCamel(field.getName()); String getter = "bean.get" + uname + "()"; String type = javaType(field); if (!field.isRequired()) { p("if (bean.has" + uname + "()) {"); indent(); } if (field.getRule() == FieldDescriptor.REPEATED_RULE) { p("for (" + type + " i : bean.get" + uname + "List()) {"); indent(); getter = "i"; } if (field.getType() == FieldDescriptor.STRING_TYPE) { p("output.writeString(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.BYTES_TYPE) { p("output.writeBytes(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.BOOL_TYPE) { p("output.writeBool(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.DOUBLE_TYPE) { p("output.writeDouble(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.FLOAT_TYPE) { p("output.writeFloat(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.INT32_TYPE) { p("output.writeInt32(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.INT64_TYPE) { p("output.writeInt64(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.SINT32_TYPE) { p("output.writeSInt32(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.SINT64_TYPE) { p("output.writeSInt64(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.UINT32_TYPE) { p("output.writeUInt32(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.UINT64_TYPE) { p("output.writeUInt64(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.FIXED32_TYPE) { p("output.writeFixed32(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.FIXED64_TYPE) { p("output.writeFixed64(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.SFIXED32_TYPE) { p("output.writeSFixed32(" + field.getTag() + ", " + getter + ");"); } else if (field.getType() == FieldDescriptor.SFIXED64_TYPE) { p("output.writeSFixed64(" + field.getTag() + ", " + getter + ");"); } else if (field.getTypeDescriptor().isEnum()) { p("output.writeEnum(" + field.getTag() + ", " + getter + ".getNumber());"); } else if (field.getGroup() != null) { errors.add("This code generator does not support group fields."); // p("writeGroup(output, "+field.getTag()+", "+getter+");"); } else { p("org.fusesource.hawtbuf.proto.MessageBufferSupport.writeMessage(output, " + field.getTag() + ", " + getter + ".freeze());"); } if (field.getRule() == FieldDescriptor.REPEATED_RULE) { unindent(); p("}"); } if (!field.isRequired()) { unindent(); p("}"); } } p("if( original !=null ) {"); indent(); p("output.checkNoSpaceLeft();"); p("output = original;"); p("output.writeRawBytes(buffer);"); unindent(); p("}"); unindent(); p("} else {"); indent(); p("output.writeRawBytes(buffer);"); unindent(); p("}"); unindent(); p("}"); p(); } /** * @param m * @param className */ private void generateMethodMergeFromStream(MessageDescriptor m, String className) { p("public " + className + " mergeUnframed(java.io.InputStream input) throws java.io.IOException {"); indent(); p("return mergeUnframed(new org.fusesource.hawtbuf.proto.CodedInputStream(input));"); unindent(); p("}"); p(); p("public " + className + " mergeUnframed(org.fusesource.hawtbuf.proto.CodedInputStream input) throws java.io.IOException {"); indent(); { p("copyCheck();"); p("while (true) {"); indent(); { p("int tag = input.readTag();"); p("if ((tag & 0x07) == 4) {"); p(" return this;"); p("}"); p("switch (tag) {"); p("case 0:"); p(" return this;"); p("default: {"); p(" break;"); p("}"); for (FieldDescriptor field : m.getFields().values()) { String uname = uCamel(field.getName()); String setter = "set" + uname; boolean repeated = field.getRule() == FieldDescriptor.REPEATED_RULE; if (repeated) { setter = "create" + uname + "List().add"; } if (field.getType() == FieldDescriptor.STRING_TYPE) { p("case " + makeTag(field.getTag(), WIRETYPE_LENGTH_DELIMITED) + ":"); indent(); p(setter + "(input.readString());"); } else if (field.getType() == FieldDescriptor.BYTES_TYPE) { p("case " + makeTag(field.getTag(), WIRETYPE_LENGTH_DELIMITED) + ":"); indent(); String override = getOption(field.getOptions(), "java_override_type", null); if ("AsciiBuffer".equals(override)) { p(setter + "(new org.fusesource.hawtbuf.AsciiBuffer(input.readBytes()));"); } else if ("UTF8Buffer".equals(override)) { p(setter + "(new org.fusesource.hawtbuf.UTF8Buffer(input.readBytes()));"); } else { p(setter + "(input.readBytes());"); } } else if (field.getType() == FieldDescriptor.BOOL_TYPE) { p("case " + makeTag(field.getTag(), WIRETYPE_VARINT) + ":"); indent(); p(setter + "(input.readBool());"); } else if (field.getType() == FieldDescriptor.DOUBLE_TYPE) { p("case " + makeTag(field.getTag(), WIRETYPE_FIXED64) + ":"); indent(); p(setter + "(input.readDouble());"); } else if (field.getType() == FieldDescriptor.FLOAT_TYPE) { p("case " + makeTag(field.getTag(), WIRETYPE_FIXED32) + ":"); indent(); p(setter + "(input.readFloat());"); } else if (field.getType() == FieldDescriptor.INT32_TYPE) { p("case " + makeTag(field.getTag(), WIRETYPE_VARINT) + ":"); indent(); p(setter + "(input.readInt32());"); } else if (field.getType() == FieldDescriptor.INT64_TYPE) { p("case " + makeTag(field.getTag(), WIRETYPE_VARINT) + ":"); indent(); p(setter + "(input.readInt64());"); } else if (field.getType() == FieldDescriptor.SINT32_TYPE) { p("case " + makeTag(field.getTag(), WIRETYPE_VARINT) + ":"); indent(); p(setter + "(input.readSInt32());"); } else if (field.getType() == FieldDescriptor.SINT64_TYPE) { p("case " + makeTag(field.getTag(), WIRETYPE_VARINT) + ":"); indent(); p(setter + "(input.readSInt64());"); } else if (field.getType() == FieldDescriptor.UINT32_TYPE) { p("case " + makeTag(field.getTag(), WIRETYPE_VARINT) + ":"); indent(); p(setter + "(input.readUInt32());"); } else if (field.getType() == FieldDescriptor.UINT64_TYPE) { p("case " + makeTag(field.getTag(), WIRETYPE_VARINT) + ":"); indent(); p(setter + "(input.readUInt64());"); } else if (field.getType() == FieldDescriptor.FIXED32_TYPE) { p("case " + makeTag(field.getTag(), WIRETYPE_FIXED32) + ":"); indent(); p(setter + "(input.readFixed32());"); } else if (field.getType() == FieldDescriptor.FIXED64_TYPE) { p("case " + makeTag(field.getTag(), WIRETYPE_FIXED64) + ":"); indent(); p(setter + "(input.readFixed64());"); } else if (field.getType() == FieldDescriptor.SFIXED32_TYPE) { p("case " + makeTag(field.getTag(), WIRETYPE_FIXED32) + ":"); indent(); p(setter + "(input.readSFixed32());"); } else if (field.getType() == FieldDescriptor.SFIXED64_TYPE) { p("case " + makeTag(field.getTag(), WIRETYPE_FIXED64) + ":"); indent(); p(setter + "(input.readSFixed64());"); } else if (field.getTypeDescriptor().isEnum()) { p("case " + makeTag(field.getTag(), WIRETYPE_VARINT) + ":"); indent(); String type = javaType(field); p("{"); indent(); p("int t = input.readEnum();"); p("" + type + " value = " + type + ".valueOf(t);"); p("if( value !=null ) {"); indent(); p(setter + "(value);"); unindent(); p("}"); // TODO: else store it as an known unindent(); p("}"); } else if (field.getGroup() != null) { errors.add("This code generator does not support group fields."); // p("case "+ makeTag(field.getTag(), WIRETYPE_START_GROUP)+ ":"); // indent(); // String type = javaType(field); // if (repeated) { // p(setter + "(readGroup(input, " + field.getTag()+ ", new " + type + "()));"); // } else { // p("if (has" + uname + "()) {"); // indent(); // p("readGroup(input, " + field.getTag() + ", get" // + uname + "());"); // unindent(); // p("} else {"); // indent(); // p(setter + "(readGroup(input, " + field.getTag() // + ",new " + type + "()));"); // unindent(); // p("}"); // } // p(""); } else { p("case " + makeTag(field.getTag(), WIRETYPE_LENGTH_DELIMITED) + ":"); indent(); String type = javaFactoryType(field.getTypeDescriptor()); if (repeated) { p(setter + "(" + qualified(type, factoryFeild) + ".parseFramed(input));"); } else { p("if (has" + uname + "()) {"); indent(); p("set" + uname + "(get" + uname + "().copy().mergeFrom(" + qualified(type, factoryFeild) + ".parseFramed(input)));"); unindent(); p("} else {"); indent(); p(setter + "(" + qualified(type, factoryFeild) + ".parseFramed(input));"); unindent(); p("}"); } } p("break;"); unindent(); } p("}"); } unindent(); p("}"); } unindent(); p("}"); } /** * @param m * @param getterClassName */ private void generateMethodMergeFromBean(MessageDescriptor m, String getterClassName, String beanClassName) { p("public " + beanClassName + " mergeFrom(" + getterClassName + " other) {"); indent(); p("copyCheck();"); for (FieldDescriptor field : m.getFields().values()) { String uname = uCamel(field.getName()); p("if (other.has" + uname + "()) {"); indent(); if (field.isScalarType() || field.getTypeDescriptor().isEnum()) { if (field.isRepeated()) { p("get" + uname + "List().addAll(other.get" + uname + "List());"); } else { p("set" + uname + "(other.get" + uname + "());"); } } else { String type = qualified(javaFactoryType(field.getTypeDescriptor()), getterCN); // It's complex type... if (field.isRepeated()) { p("for(" + type + " element: other.get" + uname + "List() ) {"); indent(); p("get" + uname + "List().add(element.copy());"); unindent(); p("}"); } else { p("if (has" + uname + "()) {"); indent(); p("set" + uname + "(get" + uname + "().copy().mergeFrom(other.get" + uname + "()));"); unindent(); p("} else {"); indent(); p("set" + uname + "(other.get" + uname + "().copy());"); unindent(); p("}"); } } unindent(); p("}"); } p("return this;"); unindent(); p("}"); p(); } /** * @param m */ private void generateMethodClear(MessageDescriptor m) { p("public void clear() {"); indent(); for (FieldDescriptor field : m.getFields().values()) { String uname = uCamel(field.getName()); p("clear" + uname + "();"); } unindent(); p("}"); p(); } private void generateReadWriteExternal(MessageDescriptor m) { p("public void readExternal(java.io.DataInput in) throws java.io.IOException {"); indent(); p("assert frozen==null : org.fusesource.hawtbuf.proto.MessageBufferSupport.FORZEN_ERROR_MESSAGE;"); p("bean = this;"); p("frozen = null;"); for (FieldDescriptor field : m.getFields().values()) { String lname = lCamel(field.getName()); String type = javaType(field); boolean repeated = field.getRule() == FieldDescriptor.REPEATED_RULE; // Create the fields.. if (repeated) { p("{"); indent(); p("int size = in.readShort();"); p("if( size>=0 ) {"); indent(); p("f_" + lname + " = new java.util.ArrayList<" + javaCollectionType(field) + ">(size);"); p("for(int i=0; i<size; i++) {"); indent(); if (field.isInteger32Type()) { p("f_" + lname + ".add(in.readInt());"); } else if (field.isInteger64Type()) { p("f_" + lname + ".add(in.readLong());"); } else if (field.getType() == FieldDescriptor.DOUBLE_TYPE) { p("f_" + lname + ".add(in.readDouble());"); } else if (field.getType() == FieldDescriptor.FLOAT_TYPE) { p("f_" + lname + ".add(in.readFloat());"); } else if (field.getType() == FieldDescriptor.BOOL_TYPE) { p("f_" + lname + ".add(in.readBoolean());"); } else if (field.getType() == FieldDescriptor.STRING_TYPE) { p("f_" + lname + ".add(in.readUTF());"); } else if (field.getType() == FieldDescriptor.BYTES_TYPE) { p("byte b[] = new byte[in.readInt()];"); p("in.readFully(b);"); p("f_" + lname + ".add(new " + type + "(b));"); } else if (field.getTypeDescriptor().isEnum()) { p("f_" + lname + ".add(" + type + ".valueOf(in.readShort()));"); } else { String beanName = qualified(javaFactoryType(field.getTypeDescriptor()), beanCN); p(beanName + " o = new " + beanName + "();"); p("o.readExternal(in);"); p("f_" + lname + ".add(o);"); } unindent(); p("}"); unindent(); p("} else {"); indent(); p("f_" + lname + " = null;"); unindent(); p("}"); unindent(); p("}"); } else { if (field.isInteger32Type()) { p("f_" + lname + " = in.readInt();"); p("b_" + lname + " = true;"); } else if (field.isInteger64Type()) { p("f_" + lname + " = in.readLong();"); p("b_" + lname + " = true;"); } else if (field.getType() == FieldDescriptor.DOUBLE_TYPE) { p("f_" + lname + " = in.readDouble();"); p("b_" + lname + " = true;"); } else if (field.getType() == FieldDescriptor.FLOAT_TYPE) { p("f_" + lname + " = in.readFloat();"); p("b_" + lname + " = true;"); } else if (field.getType() == FieldDescriptor.BOOL_TYPE) { p("f_" + lname + " = in.readBoolean();"); p("b_" + lname + " = true;"); } else if (field.getType() == FieldDescriptor.STRING_TYPE) { p("if( in.readBoolean() ) {"); indent(); p("f_" + lname + " = in.readUTF();"); unindent(); p("} else {"); indent(); p("f_" + lname + " = null;"); unindent(); p("}"); } else if (field.getType() == FieldDescriptor.BYTES_TYPE) { p("{"); indent(); p("int size = in.readInt();"); p("if( size>=0 ) {"); indent(); p("byte b[] = new byte[size];"); p("in.readFully(b);"); p("f_" + lname + " = new " + type + "(b);"); unindent(); p("} else {"); indent(); p("f_" + lname + " = null;"); unindent(); p("}"); unindent(); p("}"); } else if (field.getTypeDescriptor().isEnum()) { p("if( in.readBoolean() ) {"); indent(); p("f_" + lname + " = " + type + ".valueOf(in.readShort());"); unindent(); p("} else {"); indent(); p("f_" + lname + " = null;"); unindent(); p("}"); } else { p("if( in.readBoolean() ) {"); indent(); String factoryType = javaFactoryType(field.getTypeDescriptor()); p("" + qualified(factoryType, beanCN) + " o = new " + qualified(factoryType, beanCN) + "();"); p("o.readExternal(in);"); p("f_" + lname + " = o;"); unindent(); p("} else {"); indent(); p("f_" + lname + " = null;"); unindent(); p("}"); } } } unindent(); p("}"); p(); p("public void writeExternal(java.io.DataOutput out) throws java.io.IOException {"); indent(); for (FieldDescriptor field : m.getFields().values()) { String lname = lCamel(field.getName()); boolean repeated = field.getRule() == FieldDescriptor.REPEATED_RULE; // Create the fields.. if (repeated) { p("if( bean.f_" + lname + "!=null ) {"); indent(); p("out.writeShort(bean.f_" + lname + ".size());"); p("for(" + javaCollectionType(field) + " o : bean.f_" + lname + ") {"); indent(); if (field.isInteger32Type()) { p("out.writeInt(o);"); } else if (field.isInteger64Type()) { p("out.writeLong(o);"); } else if (field.getType() == FieldDescriptor.DOUBLE_TYPE) { p("out.writeDouble(o);"); } else if (field.getType() == FieldDescriptor.FLOAT_TYPE) { p("out.writeFloat(o);"); } else if (field.getType() == FieldDescriptor.BOOL_TYPE) { p("out.writeBoolean(o);"); } else if (field.getType() == FieldDescriptor.STRING_TYPE) { p("out.writeUTF(o);"); } else if (field.getType() == FieldDescriptor.BYTES_TYPE) { p("out.writeInt(o.getLength());"); p("out.write(o.getData(), o.getOffset(), o.getLength());"); } else if (field.getTypeDescriptor().isEnum()) { p("out.writeShort(o.getNumber());"); } else { p("o.copy().writeExternal(out);"); } unindent(); p("}"); unindent(); p("} else {"); indent(); p("out.writeShort(-1);"); unindent(); p("}"); } else { if (field.isInteger32Type()) { p("out.writeInt(bean.f_" + lname + ");"); } else if (field.isInteger64Type()) { p("out.writeLong(bean.f_" + lname + ");"); } else if (field.getType() == FieldDescriptor.DOUBLE_TYPE) { p("out.writeDouble(bean.f_" + lname + ");"); } else if (field.getType() == FieldDescriptor.FLOAT_TYPE) { p("out.writeFloat(bean.f_" + lname + ");"); } else if (field.getType() == FieldDescriptor.BOOL_TYPE) { p("out.writeBoolean(bean.f_" + lname + ");"); } else if (field.getType() == FieldDescriptor.STRING_TYPE) { p("if( bean.f_" + lname + "!=null ) {"); indent(); p("out.writeBoolean(true);"); p("out.writeUTF(bean.f_" + lname + ");"); unindent(); p("} else {"); indent(); p("out.writeBoolean(false);"); unindent(); p("}"); } else if (field.getType() == FieldDescriptor.BYTES_TYPE) { p("if( bean.f_" + lname + "!=null ) {"); indent(); p("out.writeInt(bean.f_" + lname + ".getLength());"); p("out.write(bean.f_" + lname + ".getData(), bean.f_" + lname + ".getOffset(), bean.f_" + lname + ".getLength());"); unindent(); p("} else {"); indent(); p("out.writeInt(-1);"); unindent(); p("}"); } else if (field.getTypeDescriptor().isEnum()) { p("if( bean.f_" + lname + "!=null ) {"); indent(); p("out.writeBoolean(true);"); p("out.writeShort(bean.f_" + lname + ".getNumber());"); unindent(); p("} else {"); indent(); p("out.writeBoolean(false);"); unindent(); p("}"); } else { p("if( bean.f_" + lname + "!=null ) {"); indent(); p("out.writeBoolean(true);"); p("bean.f_" + lname + ".copy().writeExternal(out);"); unindent(); p("} else {"); indent(); p("out.writeBoolean(false);"); unindent(); p("}"); } } } unindent(); p("}"); p(); } // private void generateMethodAssertInitialized(MessageDescriptor m, String className) { // // p("public java.util.ArrayList<String> missingFields() {"); // indent(); // p("java.util.ArrayList<String> missingFields = super.missingFields();"); // // for (FieldDescriptor field : m.getFields().values()) { // String uname = uCamel(field.getName()); // if( field.isRequired() ) { // p("if( !has" + uname + "() ) {"); // indent(); // p("missingFields.add(\""+field.getName()+"\");"); // unindent(); // p("}"); // } // } // // if( !deferredDecode ) { // for (FieldDescriptor field : m.getFields().values()) { // if( field.getTypeDescriptor()!=null && !field.getTypeDescriptor().isEnum()) { // String uname = uCamel(field.getName()); // p("if( has" + uname + "() ) {"); // indent(); // if( !field.isRepeated() ) { // p("try {"); // indent(); // p("get" + uname + "().assertInitialized();"); // unindent(); // p("} catch (org.fusesource.hawtbuf.proto.UninitializedMessageException e){"); // indent(); // p("missingFields.addAll(prefix(e.getMissingFields(),\""+field.getName()+".\"));"); // unindent(); // p("}"); // } else { // String type = javaCollectionType(field); // p("java.util.List<"+type+"> l = get" + uname + "List();"); // p("for( int i=0; i < l.size(); i++ ) {"); // indent(); // p("try {"); // indent(); // p("l.get(i).assertInitialized();"); // unindent(); // p("} catch (org.fusesource.hawtbuf.proto.UninitializedMessageException e){"); // indent(); // p("missingFields.addAll(prefix(e.getMissingFields(),\""+field.getName()+"[\"+i+\"]\"));"); // unindent(); // p("}"); // unindent(); // p("}"); // } // unindent(); // p("}"); // } // } // } // p("return missingFields;"); // unindent(); // p("}"); // p(); // } private void generateMethodToString(MessageDescriptor m) { p("public String toString() {"); indent(); p("return toString(new java.lang.StringBuilder(), \"\").toString();"); unindent(); p("}"); p(); p("public java.lang.StringBuilder toString(java.lang.StringBuilder sb, String prefix) {"); indent(); for (FieldDescriptor field : m.getFields().values()) { String uname = uCamel(field.getName()); p("if( has" + uname + "() ) {"); indent(); if (field.isRepeated()) { String type = javaCollectionType(field); p("java.util.List<" + type + "> l = get" + uname + "List();"); p("for( int i=0; i < l.size(); i++ ) {"); indent(); if (field.getTypeDescriptor() != null && !field.getTypeDescriptor().isEnum()) { p("sb.append(prefix+\"" + field.getName() + "[\"+i+\"] {\\n\");"); p("l.get(i).toString(sb, prefix+\" \");"); p("sb.append(prefix+\"}\\n\");"); } else { p("sb.append(prefix+\"" + field.getName() + "[\"+i+\"]: \");"); p("sb.append(l.get(i));"); p("sb.append(\"\\n\");"); } unindent(); p("}"); } else { if (field.getTypeDescriptor() != null && !field.getTypeDescriptor().isEnum()) { p("sb.append(prefix+\"" + field.getName() + " {\\n\");"); p("get" + uname + "().toString(sb, prefix+\" \");"); p("sb.append(prefix+\"}\\n\");"); } else { p("sb.append(prefix+\"" + field.getName() + ": \");"); p("sb.append(get" + uname + "());"); p("sb.append(\"\\n\");"); } } unindent(); p("}"); } p("return sb;"); unindent(); p("}"); p(); } /** * @param field */ private void generateBufferGetters(FieldDescriptor field) { String uname = uCamel(field.getName()); String type = field.getRule() == FieldDescriptor.REPEATED_RULE ? javaCollectionType(field) : javaType(field); boolean repeated = field.getRule() == FieldDescriptor.REPEATED_RULE; // Create the fields.. p("// " + field.getRule() + " " + field.getType() + " " + field.getName() + " = " + field.getTag() + ";"); if (repeated) { // Create the field accessors p("public boolean has" + uname + "() {"); indent(); p("return bean().has" + uname + "();"); unindent(); p("}"); p(); p("public java.util.List<" + type + "> get" + uname + "List() {"); indent(); p("return bean().get" + uname + "List();"); unindent(); p("}"); p(); p("public int get" + uname + "Count() {"); indent(); p("return bean().get" + uname + "Count();"); unindent(); p("}"); p(); p("public " + type + " get" + uname + "(int index) {"); indent(); p("return bean().get" + uname + "(index);"); unindent(); p("}"); p(); } else { // Create the field accessors p("public boolean has" + uname + "() {"); indent(); p("return bean().has" + uname + "();"); unindent(); p("}"); p(); p("public " + type + " get" + uname + "() {"); indent(); p("return bean().get" + uname + "();"); unindent(); p("}"); p(); } } /** * @param field */ private void generateFieldGetterSignatures(FieldDescriptor field) { String uname = uCamel(field.getName()); String type = field.getRule() == FieldDescriptor.REPEATED_RULE ? javaCollectionType(field) : javaType(field); boolean repeated = field.getRule() == FieldDescriptor.REPEATED_RULE; // Create the fields.. p("// " + field.getRule() + " " + field.getType() + " " + field.getName() + " = " + field.getTag() + ";"); if (repeated) { // Create the field accessors p("public boolean has" + uname + "();"); p("public java.util.List<" + type + "> get" + uname + "List();"); p("public int get" + uname + "Count();"); p("public " + type + " get" + uname + "(int index);"); } else { // Create the field accessors p("public boolean has" + uname + "();"); p("public " + type + " get" + uname + "();"); } } /** * @param field */ private void generateFieldAccessor(String beanClassName, FieldDescriptor field) { String lname = lCamel(field.getName()); String uname = uCamel(field.getName()); String type = field.getRule() == FieldDescriptor.REPEATED_RULE ? javaCollectionType(field) : javaType(field); String typeDefault = javaTypeDefault(field); boolean primitive = isPrimitive(type); boolean repeated = field.getRule() == FieldDescriptor.REPEATED_RULE; // Create the fields.. p("// " + field.getRule() + " " + field.getType() + " " + field.getName() + " = " + field.getTag() + ";"); if (repeated) { p("private java.util.List<" + type + "> f_" + lname + ";"); p(); // Create the field accessors p("public boolean has" + uname + "() {"); indent(); p("return bean.f_" + lname + "!=null && !bean.f_" + lname + ".isEmpty();"); unindent(); p("}"); p(); p("public java.util.List<" + type + "> get" + uname + "List() {"); indent(); p("return bean.f_" + lname + ";"); unindent(); p("}"); p(); p("public java.util.List<" + type + "> create" + uname + "List() {"); indent(); p("copyCheck();"); p("if( this.f_" + lname + " == null ) {"); indent(); p("this.f_" + lname + " = new java.util.ArrayList<" + type + ">();"); unindent(); p("}"); p("return bean.f_" + lname + ";"); unindent(); p("}"); p(); p("public " + beanClassName + " set" + uname + "List(java.util.List<" + type + "> " + lname + ") {"); indent(); p("copyCheck();"); p("this.f_" + lname + " = " + lname + ";"); p("return this;"); unindent(); p("}"); p(); p("public int get" + uname + "Count() {"); indent(); p("if( bean.f_" + lname + " == null ) {"); indent(); p("return 0;"); unindent(); p("}"); p("return bean.f_" + lname + ".size();"); unindent(); p("}"); p(); p("public " + type + " get" + uname + "(int index) {"); indent(); p("if( bean.f_" + lname + " == null ) {"); indent(); p("return null;"); unindent(); p("}"); p("return bean.f_" + lname + ".get(index);"); unindent(); p("}"); p(); p("public " + beanClassName + " set" + uname + "(int index, " + type + " value) {"); indent(); p("this.create" + uname + "List().set(index, value);"); p("return this;"); unindent(); p("}"); p(); p("public " + beanClassName + " add" + uname + "(" + type + " value) {"); indent(); p("this.create" + uname + "List().add(value);"); p("return this;"); unindent(); p("}"); p(); p("public " + beanClassName + " addAll" + uname + "(java.lang.Iterable<? extends " + type + "> collection) {"); indent(); p("org.fusesource.hawtbuf.proto.MessageBufferSupport.addAll(collection, this.create" + uname + "List());"); p("return this;"); unindent(); p("}"); p(); p("public void clear" + uname + "() {"); indent(); p("copyCheck();"); p("this.f_" + lname + " = null;"); unindent(); p("}"); p(); } else { p("private " + type + " f_" + lname + " = " + typeDefault + ";"); if (primitive) { p("private boolean b_" + lname + ";"); } p(); // Create the field accessors p("public boolean has" + uname + "() {"); indent(); if (primitive) { p("return bean.b_" + lname + ";"); } else { p("return bean.f_" + lname + "!=null;"); } unindent(); p("}"); p(); p("public " + type + " get" + uname + "() {"); indent(); p("return bean.f_" + lname + ";"); unindent(); p("}"); p(); p("public " + beanClassName + " set" + uname + "(" + type + " " + lname + ") {"); indent(); p("copyCheck();"); if (primitive) { if (auto_clear_optional_fields && field.isOptional()) { if (field.isStringType() && !"null".equals(typeDefault)) { p("this.b_" + lname + " = (" + lname + " != " + typeDefault + ");"); } else { p("this.b_" + lname + " = (" + lname + " != " + typeDefault + ");"); } } else { p("this.b_" + lname + " = true;"); } } p("this.f_" + lname + " = " + lname + ";"); p("return this;"); unindent(); p("}"); p(); p("public void clear" + uname + "() {"); indent(); p("copyCheck();"); if (primitive) { p("this.b_" + lname + " = false;"); } p("this.f_" + lname + " = " + typeDefault + ";"); unindent(); p("}"); p(); } } private String javaTypeDefault(FieldDescriptor field) { OptionDescriptor defaultOption = field.getOptions().get("default"); if (defaultOption != null) { if (field.isStringType()) { return asJavaString(defaultOption.getValue()); } else if (field.getType() == FieldDescriptor.BYTES_TYPE) { return "new " + javaType(field) + "(org.fusesource.hawtbuf.UTF8Buffer.encode(" + asJavaString(defaultOption.getValue()) + "))"; } else if (field.isInteger32Type()) { int v; if (field.getType() == FieldDescriptor.UINT32_TYPE) { v = TextFormat.parseUInt32(defaultOption.getValue()); } else { v = TextFormat.parseInt32(defaultOption.getValue()); } return "" + v; } else if (field.isInteger64Type()) { long v; if (field.getType() == FieldDescriptor.UINT64_TYPE) { v = TextFormat.parseUInt64(defaultOption.getValue()); } else { v = TextFormat.parseInt64(defaultOption.getValue()); } return "" + v + "l"; } else if (field.getType() == FieldDescriptor.DOUBLE_TYPE) { double v = Double.valueOf(defaultOption.getValue()); return "" + v + "d"; } else if (field.getType() == FieldDescriptor.FLOAT_TYPE) { float v = Float.valueOf(defaultOption.getValue()); return "" + v + "f"; } else if (field.getType() == FieldDescriptor.BOOL_TYPE) { boolean v = Boolean.valueOf(defaultOption.getValue()); return "" + v; } else if (field.getTypeDescriptor() != null && field.getTypeDescriptor().isEnum()) { return javaType(field) + "." + defaultOption.getValue(); } return defaultOption.getValue(); } else { if (field.isNumberType()) { return "0"; } if (field.getType() == FieldDescriptor.BOOL_TYPE) { return "false"; } return "null"; } } static final char HEX_TABLE[] = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; private String asJavaString(String value) { StringBuilder sb = new StringBuilder(value.length() + 2); sb.append("\""); for (int i = 0; i < value.length(); i++) { char b = value.charAt(i); switch (b) { // Java does not recognize \a or \v, apparently. case '\b': sb.append("\\b"); break; case '\f': sb.append("\\f"); break; case '\n': sb.append("\\n"); break; case '\r': sb.append("\\r"); break; case '\t': sb.append("\\t"); break; case '\\': sb.append("\\\\"); break; case '\'': sb.append("\\\'"); break; case '"': sb.append("\\\""); break; default: if (b >= 0x20 && b < 'Z') { sb.append((char) b); } else { sb.append("\\u"); sb.append(HEX_TABLE[(b >>> 12) & 0x0F]); sb.append(HEX_TABLE[(b >>> 8) & 0x0F]); sb.append(HEX_TABLE[(b >>> 4) & 0x0F]); sb.append(HEX_TABLE[b & 0x0F]); } break; } } sb.append("\""); return sb.toString(); } private void generateEnum(EnumDescriptor ed) { String uname = uCamel(ed.getName()); String staticOption = "static "; if (multipleFiles && ed.getParent() == null) { staticOption = ""; } // TODO Auto-generated method stub p(); p("public " + staticOption + "enum " + uname + " {"); indent(); p(); int counter = 0; for (EnumFieldDescriptor field : ed.getFields().values()) { boolean last = counter + 1 == ed.getFields().size(); p(field.getName() + "(\"" + field.getName() + "\", " + field.getValue() + ")" + (last ? ";" : ",")); counter++; } p(); p("private final String name;"); p("private final int value;"); p(); p("private " + uname + "(String name, int value) {"); p(" this.name = name;"); p(" this.value = value;"); p("}"); p(); p("public final int getNumber() {"); p(" return value;"); p("}"); p(); p("public final String toString() {"); p(" return name;"); p("}"); p(); p("public static " + uname + " valueOf(int value) {"); p(" switch (value) {"); // It's possible to define multiple ENUM fields with the same value.. // we only want to put the first one into the switch statement. HashSet<Integer> values = new HashSet<Integer>(); for (EnumFieldDescriptor field : ed.getFields().values()) { if (!values.contains(field.getValue())) { p(" case " + field.getValue() + ":"); p(" return " + field.getName() + ";"); values.add(field.getValue()); } } p(" default:"); p(" return null;"); p(" }"); p("}"); p(); String createMessage = getOption(ed.getOptions(), "java_create_message", null); if ("true".equals(createMessage)) { p("public interface " + uname + "Creatable {"); indent(); p("" + uname + " to" + uname + "();"); unindent(); p("}"); p(); p("public " + uname + "Creatable createBean() {"); indent(); p("switch (this) {"); indent(); for (EnumFieldDescriptor field : ed.getFields().values()) { p("case " + field.getName() + ":"); String type = field.getAssociatedType().getName(); p(" return new " + qualified(type, beanCN) + "();"); } p("default:"); p(" return null;"); unindent(); p("}"); unindent(); p("}"); p(); generateParseDelegate(ed, "parseUnframed", "org.fusesource.hawtbuf.Buffer", "org.fusesource.hawtbuf.proto.InvalidProtocolBufferException"); generateParseDelegate(ed, "parseFramed", "org.fusesource.hawtbuf.Buffer", "org.fusesource.hawtbuf.proto.InvalidProtocolBufferException"); generateParseDelegate(ed, "parseUnframed", "byte[]", "org.fusesource.hawtbuf.proto.InvalidProtocolBufferException"); generateParseDelegate(ed, "parseFramed", "byte[]", "org.fusesource.hawtbuf.proto.InvalidProtocolBufferException"); generateParseDelegate(ed, "parseFramed", "org.fusesource.hawtbuf.proto.CodedInputStream", "org.fusesource.hawtbuf.proto.InvalidProtocolBufferException, java.io.IOException"); generateParseDelegate(ed, "parseFramed", "java.io.InputStream", "org.fusesource.hawtbuf.proto.InvalidProtocolBufferException, java.io.IOException"); } unindent(); p("}"); p(); } private void generateParseDelegate(EnumDescriptor descriptor, String methodName, String inputType, String exceptions) { p("public org.fusesource.hawtbuf.proto.MessageBuffer " + methodName + "(" + inputType + " data) throws " + exceptions + " {"); indent(); p("switch (this) {"); indent(); for (EnumFieldDescriptor field : descriptor.getFields().values()) { p("case " + field.getName() + ":"); String type = constantToUCamelCase(field.getName()); p(" return " + qualified(type, factoryFeild) + "." + methodName + "(data);"); } p("default:"); p(" return null;"); unindent(); p("}"); unindent(); p("}"); p(); } private String javaCollectionType(FieldDescriptor field) { if (field.isInteger32Type()) { return "java.lang.Integer"; } if (field.isInteger64Type()) { return "java.lang.Long"; } if (field.getType() == FieldDescriptor.DOUBLE_TYPE) { return "java.lang.Double"; } if (field.getType() == FieldDescriptor.FLOAT_TYPE) { return "java.lang.Float"; } if (field.getType() == FieldDescriptor.STRING_TYPE) { // TODO: support handling string fields as buffers. // String override = getOption(field.getOptions(), "java_override_type", null); // if( "AsciiBuffer".equals(override) ) { // return "org.fusesource.hawtbuf.AsciiBuffer"; // } else if( "UTF8Buffer".equals(override) ) { // return "org.fusesource.hawtbuf.UTF8Buffer"; // } else if( "Buffer".equals(override) ) { // return "org.fusesource.hawtbuf.Buffer"; // } else { return "java.lang.String"; // } } if (field.getType() == FieldDescriptor.BYTES_TYPE) { String override = getOption(field.getOptions(), "java_override_type", null); if ("AsciiBuffer".equals(override)) { return "org.fusesource.hawtbuf.AsciiBuffer"; } else if ("UTF8Buffer".equals(override)) { return "org.fusesource.hawtbuf.UTF8Buffer"; } else { return "org.fusesource.hawtbuf.Buffer"; } } if (field.getType() == FieldDescriptor.BOOL_TYPE) { return "java.lang.Boolean"; } TypeDescriptor descriptor = field.getTypeDescriptor(); return qualified(javaFactoryType(descriptor), getterCN); } private String javaType(FieldDescriptor field) { if (field.isInteger32Type()) { return "int"; } if (field.isInteger64Type()) { return "long"; } if (field.getType() == FieldDescriptor.DOUBLE_TYPE) { return "double"; } if (field.getType() == FieldDescriptor.FLOAT_TYPE) { return "float"; } if (field.getType() == FieldDescriptor.STRING_TYPE) { // TODO: support handling string fields as buffers. // String override = getOption(field.getOptions(), "java_override_type", null); // if( "AsciiBuffer".equals(override) ) { // return "org.fusesource.hawtbuf.AsciiBuffer"; // } else if( "UTF8Buffer".equals(override) ) { // return "org.fusesource.hawtbuf.UTF8Buffer"; // } else if( "Buffer".equals(override) ) { // return "org.fusesource.hawtbuf.Buffer"; // } else { return "java.lang.String"; // } } if (field.getType() == FieldDescriptor.BYTES_TYPE) { String override = getOption(field.getOptions(), "java_override_type", null); if ("AsciiBuffer".equals(override)) { return "org.fusesource.hawtbuf.AsciiBuffer"; } else if ("UTF8Buffer".equals(override)) { return "org.fusesource.hawtbuf.UTF8Buffer"; } else { return "org.fusesource.hawtbuf.Buffer"; } } if (field.getType() == FieldDescriptor.BOOL_TYPE) { return "boolean"; } TypeDescriptor descriptor = field.getTypeDescriptor(); return qualified(javaFactoryType(descriptor), getterCN); } private String javaFactoryType(TypeDescriptor descriptor) { ProtoDescriptor p = descriptor.getProtoDescriptor(); if (p != proto) { // Try to keep it short.. String othePackage = javaPackage(p); if (equals(othePackage, javaPackage(proto))) { return javaClassName(p) + "." + descriptor.getQName(); } // Use the fully qualified class name. return othePackage + "." + javaClassName(p) + "." + descriptor.getQName(); } return descriptor.getQName(); } private String qualified(String type, String suffix) { // int ix = type.lastIndexOf("."); // if (ix == -1) { // // type = Foo, result = Foo.FooBean // return type+"."+type+suffix; // } // // type = Foo.Bar, result = Foo.Bar.BarBean // return type+"."+type.substring(ix+1)+suffix; return type + "." + suffix; } private boolean equals(String o1, String o2) { if (o1 == o2) return true; if (o1 == null || o2 == null) return false; return o1.equals(o2); } private String javaClassName(ProtoDescriptor proto) { return getOption(proto.getOptions(), "java_outer_classname", uCamel(removeFileExtension(proto.getName()))); } private boolean isMultipleFilesEnabled(ProtoDescriptor proto) { return "true".equals(getOption(proto.getOptions(), "java_multiple_files", "false")); } private String javaPackage(ProtoDescriptor proto) { String name = proto.getPackageName(); if (name != null) { name = name.replace('-', '.'); name = name.replace('/', '.'); } return getOption(proto.getOptions(), "java_package", name); } // ---------------------------------------------------------------- // Internal Helper methods // ---------------------------------------------------------------- private void indent() { indent++; } private void unindent() { indent--; } private void p(String line) { // Indent... for (int i = 0; i < indent; i++) { w.print(" "); } // Then print. w.println(line); } private void p() { w.println(); } private String getOption(Map<String, OptionDescriptor> options, String optionName, String defaultValue) { OptionDescriptor optionDescriptor = options.get(optionName); if (optionDescriptor == null) { return defaultValue; } return optionDescriptor.getValue(); } static private String removeFileExtension(String name) { return name.replaceAll("\\..*", ""); } static private String uCamel(String name) { boolean upNext = true; StringBuilder sb = new StringBuilder(); for (int i = 0; i < name.length(); i++) { char c = name.charAt(i); if (Character.isJavaIdentifierPart(c) && Character.isLetterOrDigit(c)) { if (upNext) { c = Character.toUpperCase(c); upNext = false; } sb.append(c); } else { upNext = true; } } return sb.toString(); } static private String lCamel(String name) { if (name == null || name.length() < 1) return name; String uCamel = uCamel(name); return uCamel.substring(0, 1).toLowerCase() + uCamel.substring(1); } private String constantToUCamelCase(String name) { boolean upNext = true; StringBuilder sb = new StringBuilder(); for (int i = 0; i < name.length(); i++) { char c = name.charAt(i); if (Character.isJavaIdentifierPart(c) && Character.isLetterOrDigit(c)) { if (upNext) { c = Character.toUpperCase(c); upNext = false; } else { c = Character.toLowerCase(c); } sb.append(c); } else { upNext = true; } } return sb.toString(); } private String constantCase(String name) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < name.length(); i++) { char c = name.charAt(i); if (i != 0 && Character.isUpperCase(c)) { sb.append("_"); } sb.append(Character.toUpperCase(c)); } return sb.toString(); } public File getOut() { return out; } public void setOut(File outputDirectory) { this.out = outputDirectory; } public File[] getPath() { return path; } public void setPath(File[] path) { this.path = path; } }