Author: tchemit Date: 2009-12-08 18:21:03 +0100 (Tue, 08 Dec 2009) New Revision: 1679 Added: trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/AbstractJAXXBindingWriter.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataListener.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DefaultJAXXBindingWriter.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/JAXXBindingWriter.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/JavaParserUtil.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/SimpleJAXXObjectBindingWriter.java trunk/jaxx-compiler/src/test/java/jaxx/compiler/binding/ trunk/jaxx-compiler/src/test/java/jaxx/compiler/binding/JavaParserUtilTest.java trunk/jaxx-compiler/src/test/java/jaxx/compiler/java/ trunk/jaxx-compiler/src/test/java/jaxx/compiler/java/JavaFieldTest.java trunk/jaxx-compiler/src/test/java/jaxx/compiler/java/JavaMethodTest.java trunk/jaxx-compiler/src/test/java/jaxx/compiler/reflect/JavaFileParserTest.java trunk/jaxx-compiler/src/test/java/jaxx/compiler/reflect/MyEnum.java trunk/jaxx-runtime/src/main/java/jaxx/runtime/JAXXBinding.java trunk/jaxx-runtime/src/main/java/jaxx/runtime/binding/ trunk/jaxx-runtime/src/main/java/jaxx/runtime/binding/DefaultJAXXBinding.java trunk/jaxx-runtime/src/main/java/jaxx/runtime/binding/SimpleJAXXObjectBinding.java Removed: trunk/jaxx-compiler/src/test/java/jaxx/compiler/JavaFileParserTest.java trunk/jaxx-compiler/src/test/java/jaxx/compiler/JavaMethodTest.java trunk/jaxx-runtime/src/main/java/jaxx/runtime/JAXXBinding.java Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompiler.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompilerFinalizer.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXEngine.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/SymbolTable.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataBinding.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataBindingHelper.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataSource.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/decorators/DefaultCompiledObjectDecorator.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/DefaultFinalizer.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/SwingFinalizer.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/ValidatorFinalizer.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaElement.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaField.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaFile.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaFileGenerator.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaMethod.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/reflect/ClassDescriptorLoader.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/reflect/JavaFileParser.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/tags/TagManager.java trunk/jaxx-runtime/src/main/java/jaxx/runtime/JAXXObject.java trunk/jaxx-runtime/src/main/java/jaxx/runtime/Util.java trunk/jaxx-runtime/src/test/java/jaxx/runtime/context/DefaultJAXXContextTest.java Log: - refactor binding framework Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompiler.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompiler.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompiler.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -358,7 +358,7 @@ symbolTable.setSuperclassName(fullClassName); } String id = tag.getAttribute(DefaultObjectHandler.ID_ATTRIBUTE); - if (id.length() > 0) { + if (!id.isEmpty()) { symbolTable.getClassTagIds().put(id, fullClassName); if (tag.getAttributeNode(DefaultObjectHandler.JAVA_BEAN_ATTRIBUTE) != null) { // add java bean support for this property @@ -369,8 +369,49 @@ symbolTable.getScriptMethods().add(new MethodDescriptor("is" + capitalizeName, Modifier.PUBLIC, fullClassName, new String[0], classLoader)); } symbolTable.getScriptMethods().add(new MethodDescriptor("set" + capitalizeName, Modifier.PUBLIC, "void", new String[]{fullClassName}, classLoader)); + } else { + // add simple get support + String capitalizeName = StringUtils.capitalize(id); + // add method + symbolTable.getScriptMethods().add(new MethodDescriptor("get" + capitalizeName, Modifier.PUBLIC, fullClassName, new String[0], classLoader)); } } + String interfacesStr = tag.getAttribute(DefaultObjectHandler.IMPLEMENTS_ATTRIBUTE); + if (!interfacesStr.isEmpty()) { + // there is some interfaces to deal with + StringTokenizer stk = new StringTokenizer(interfacesStr, ","); + List<String> tmp = new ArrayList<String>(); + while (stk.hasMoreTokens()) { + String c = stk.nextToken(); + if (c.indexOf("<") != -1 && c.indexOf(">") == -1) { + // deal with a generic interface with more than one parameter + boolean done = false; + while (stk.hasMoreTokens()) { + + String next = stk.nextToken(); + if (next.indexOf(">") == -1) { + // still a parameter of the generic type + continue; + } + // ok find the ending token + done = true; + break; + } + if (!done) { + // the syntax is not valid (missed one >) + throw new CompilerException("Syntax error of interfaces " + interfacesStr); + } + c = c.substring(0, c.indexOf("<")); + } + tmp.add(c.trim()); + } + String[] interfaces = tmp.toArray(new String[tmp.size()]); + if (log.isDebugEnabled()) { + log.debug("detect interfaces : " + Arrays.toString(interfaces)); + } + symbolTable.setInterfaces(interfaces); + } + } // during the first pass, we can't create ClassDescriptors for JAXX files because they may not have been processed yet // (and we can't wait until they have been processed because of circular dependencies). So we don't do any processing @@ -410,7 +451,7 @@ Element finished = tagsBeingCompiled.pop(); if (finished != tag) { - throw new RuntimeException("internal error: just finished compiling " + tag + ", but top of tagsBeingCompiled stack is " + finished); + throw new IllegalStateException("internal error: just finished compiling " + tag + ", but top of tagsBeingCompiled stack is " + finished); } } @@ -1093,9 +1134,9 @@ // return result; } - public void revertId(String name) { - idHelper.revertId(name); - } +// public void revertId(String name) { +// idHelper.revertId(name); +// } public void setExtraInterfaces(String[] extraInterfaces) { this.extraInterfaces = extraInterfaces; @@ -1146,15 +1187,45 @@ String packageName = dotPos != -1 ? getOutputClassName().substring(0, dotPos) : null; String simpleClassName = getOutputClassName().substring(dotPos + 1); CompiledObject compiledObject = getRootObject(); + + // finalize all objects via their decorator + + for (CompiledObject object : getObjects().values()) { + CompiledObjectDecorator decorator = object.getDecorator(); + decorator.finalizeCompiler(this, root, object, javaFile, packageName, simpleClassName, getOutputClassName()); + } + + // obtain listy of finalizers to apply + + List<JAXXCompilerFinalizer> realFinalizers = new ArrayList<JAXXCompilerFinalizer>(); for (JAXXCompilerFinalizer finalizer : finalizers) { - finalizer.finalizeCompiler(compiledObject, this, javaFile, packageName, simpleClassName); + if (finalizer.accept(this)) { + realFinalizers.add(finalizer); + } } + // call the finalizers finalizeCompiler method + + for (JAXXCompilerFinalizer finalizer : realFinalizers) { + // check if finalizer can be apply of this compiler + if (finalizer.accept(this)) { + finalizer.finalizeCompiler(compiledObject, this, javaFile, packageName, simpleClassName); + } + } + + // call the compiled objects finalizeCompiler method + for (CompiledObject object : getObjects().values()) { object.finalizeCompiler(this); } - for (JAXXCompilerFinalizer finalizer : finalizers) { + // compile bindings + + getBindingHelper().finalizeBindings(); + + // call the finalizers prepareJavaFile method + + for (JAXXCompilerFinalizer finalizer : realFinalizers) { finalizer.prepareJavaFile(compiledObject, this, javaFile, packageName, simpleClassName); } } Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompilerFinalizer.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompilerFinalizer.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompilerFinalizer.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -23,37 +23,44 @@ import jaxx.compiler.java.JavaFile; /** - * Contract of any object to interact with a {@link JAXXCompiler} before the + * Contract of any object to interact with a {@link JAXXCompiler} before the * generation pass. - * + * * @author chemit * @since 2.0.0 */ public interface JAXXCompilerFinalizer { + /** + * Test if the finalizer must be apply on the given {@code compiler}. + * + * @param compiler the compiler + * @return {@code true} if the finalizer must be apply of compiler + */ + boolean accept(JAXXCompiler compiler); /** * Finalize compiler for a given compiler on the finalizer pass before any * generation. - * - * @param root the root object - * @param compiler the current compiler - * @param javaFile the java file to generate + * + * @param root the root object + * @param compiler the current compiler + * @param javaFile the java file to generate * @param packageName the package name of the file to generate - * @param className the class name of the file to generate - * @throws Exception + * @param className the class name of the file to generate + * @throws Exception if any pb */ void finalizeCompiler(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className) throws Exception; /** * Prepare java file after any compiler finalizer pass, says the last * action before generation. - * - * @param root the root object - * @param compiler the current compiler - * @param javaFile the java file to generate + * + * @param root the root object + * @param compiler the current compiler + * @param javaFile the java file to generate * @param packageName the package name of the file to generate - * @param className the class name of the file to generate - * @throws Exception + * @param className the class name of the file to generate + * @throws Exception if any pb */ void prepareJavaFile(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className) throws Exception; } Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXEngine.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXEngine.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXEngine.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -28,13 +28,7 @@ import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; -import java.util.TreeMap; +import java.util.*; /** * @author chemit @@ -42,10 +36,10 @@ */ public class JAXXEngine { - /** + /** * Logger */ - protected static final Log log = LogFactory.getLog(JAXXEngine.class); + private static final Log log = LogFactory.getLog(JAXXEngine.class); public void addJaxxFileClassName(String className) { jaxxFileClassNames.add(className); @@ -597,12 +591,12 @@ //FIXME : deal better the exception treatment... } catch (CompilerException e) { - log.error(e.getMessage()); + log.error(e.getMessage(),e); // System.err.println(e.getMessage()); // e.printStackTrace(); return -1; } catch (Throwable e) { - log.error(e.getMessage()); + log.error(e.getMessage(),e); // e.printStackTrace(); return -1; } finally { Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/SymbolTable.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/SymbolTable.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/SymbolTable.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -1,23 +1,23 @@ -/* - * *##% - * JAXX Compiler - * Copyright (C) 2008 - 2009 CodeLutin - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/lgpl-3.0.html>. - * ##%* - */ +/* + * *##% + * JAXX Compiler + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * ##%* + */ package jaxx.compiler; import jaxx.compiler.reflect.FieldDescriptor; @@ -28,7 +28,9 @@ import java.util.List; import java.util.Map; -/** Symbol table constructed during the first pass of compilation. */ +/** + * Symbol table constructed during the first pass of compilation. + */ public class SymbolTable { private String superclass; @@ -37,12 +39,19 @@ private Map<String, String> ids = new HashMap<String, String>(); private List<FieldDescriptor> scriptFields = new ArrayList<FieldDescriptor>(); private List<MethodDescriptor> scriptMethods = new ArrayList<MethodDescriptor>(); + private String[] interfaces; - /** @return the fully-qualified name of the superclass of the class described by this symbol table. */ + /** + * @return the fully-qualified name of the superclass of the class described by this symbol table. + */ public String getSuperclassName() { return superclass; } + public String[] getInterfaces() { + return interfaces; + } + public void setSuperclassName(String superclass) { this.superclass = superclass; } @@ -56,13 +65,21 @@ return ids; } - /** @return a list of <code>FieldDescriptors</code> for fields defined in <script> tags. */ + /** + * @return a list of <code>FieldDescriptors</code> for fields defined in <script> tags. + */ public List<FieldDescriptor> getScriptFields() { return scriptFields; } - /** @return a list of <code>MethodDescriptors</code> for methods defined in <script> tags. */ + /** + * @return a list of <code>MethodDescriptors</code> for methods defined in <script> tags. + */ public List<MethodDescriptor> getScriptMethods() { return scriptMethods; } + + public void setInterfaces(String[] interfaces) { + this.interfaces = interfaces; + } } Added: trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/AbstractJAXXBindingWriter.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/AbstractJAXXBindingWriter.java (rev 0) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/AbstractJAXXBindingWriter.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -0,0 +1,55 @@ +package jaxx.compiler.binding; + +import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.finalizers.DefaultFinalizer; +import jaxx.compiler.java.JavaFileGenerator; +import jaxx.compiler.java.JavaMethod; +import jaxx.runtime.JAXXBinding; + +import java.util.List; + +/** + * Created: 5 déc. 2009 + * + * @author Tony Chemit <chemit@codelutin.com> Copyright Code Lutin + * @version $Revision$ + * <p/> + * Mise a jour: $Date$ par : + * $Author: tchemit $ + */ +public abstract class AbstractJAXXBindingWriter<B extends JAXXBinding> implements JAXXBindingWriter<B> { + + private final Class<B> type; + protected boolean used; + + protected AbstractJAXXBindingWriter(Class<B> type) { + this.type = type; + } + + @Override + public boolean isUsed() { + return used; + } + + + public Class<B> getType() { + return type; + } + + protected abstract String getConstructorParams(DataBinding binding, DataListener[] trackers); + + protected void writeInvocationMethod(DataBinding binding, DataListener[] trackers, JavaFileGenerator generator, StringBuilder buffer, List<JavaMethod> bMethods) { + used = true; + String eol = JAXXCompiler.getLineSeparator(); + buffer.append(DefaultFinalizer.METHOD_NAME_REGISTER_DATA_BINDING + "(new "); + buffer.append(getType().getSimpleName()).append("(").append(getConstructorParams(binding, trackers)).append(") {").append(eol); + for (JavaMethod m : bMethods) { + buffer.append(eol).append(JavaFileGenerator.indent(generator.generateMethod(m), 4, false, eol)).append(eol); + } + buffer.append("});").append(eol); + + if (binding.getInitDataBinding() != null) { + buffer.append(binding.getInitDataBinding()); + } + } +} \ No newline at end of file Property changes on: trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/AbstractJAXXBindingWriter.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataBinding.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataBinding.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataBinding.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -84,14 +84,6 @@ */ protected String initDataBinding; /** - * code to put in applyDataBinding method on generated java file - */ - private StringBuffer addListenerCode = new StringBuffer(); - /** - * code to put in removeDataBinding method on generated java file - */ - private StringBuffer removeListenerCode = new StringBuffer(); - /** * Extra method to add to the binding */ protected final List<JavaMethod> methods = new ArrayList<JavaMethod>(); @@ -109,7 +101,6 @@ * @param quickNoDependencies internal flag to not treate process databinding in not a real binding */ public DataBinding(String id, String source, String assignment, boolean quickNoDependencies) { -// public DataBinding(String source, String id, String assignment, boolean quickNoDependencies) { this.id = id; this.source = source; this.assignment = assignment; @@ -119,14 +110,6 @@ } } -// public String getId() { -// return id; -// } - -// public DataSource getDataSource() { -// return dataSource; -// } - public String getAssignment() { return assignment; } @@ -147,14 +130,10 @@ return initDataBinding; } - public String getAddListenerCode() { - return addListenerCode.toString(); + public DataListener[] getTrackers() { + return dataSource == null ? null : dataSource.getTrackers(); } - public String getRemoveListenerCode() { - return removeListenerCode.toString(); - } - public String getRealId() { return realId; } @@ -171,19 +150,20 @@ public String toString() { ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE); b.append("id", id); - b.append("source", source); - b.append("assignement", assignment); + b.append("source", source.trim()); + b.append("assignement", assignment.trim()); b.append("quickNoDependencies", quickNoDependencies); if (compiled) { b.append("realdId", realId); b.append("constantId", getConstantId()); - if (!addListenerCode.toString().trim().isEmpty()) { - b.append("addListenerCode", addListenerCode.toString().trim()); + b.append("objectCode", dataSource.getObjectCode()); + DataListener[] trackers = dataSource.getTrackers(); + if (trackers.length > 0) { + b.append("source:trackers", trackers.length); + for (DataListener d : trackers) { + b.append("source:tracker", d); + } } - if (!removeListenerCode.toString().trim().isEmpty()) { - b.append("removeListenerCode", removeListenerCode.toString().trim()); - } - b.append("dataSource", dataSource); } return b.toString(); } @@ -194,13 +174,10 @@ * binding setup. * * @param compiler compiler which includes the data binding - * // * @param quickNoDependencies true to optimize bindings with no dependencies by simply running them at startup time * @return {@code true} if the expression has dependencies, {@code false} otherwise - * @throws jaxx.compiler.CompilerException - * if a compilation error occurs + * @throws jaxx.compiler.CompilerException if a compilation error occurs */ public boolean compile(JAXXCompiler compiler) throws CompilerException { -// public boolean compile(JAXXCompiler compiler, boolean quickNoDependencies) throws CompilerException { if (compiled) { throw new IllegalStateException(this + " has already been compiled"); @@ -208,36 +185,45 @@ DataBindingHelper bindingHelper = compiler.getBindingHelper(); + // obtain a safe id realId = bindingHelper.getSafeId(id.trim()); + + // compute the constant id of the binding constantId = TypeManager.convertVariableNameToConstantName("binding_" + realId); - dataSource = new DataSource(realId, constantId, getSource(), compiler, addListenerCode, removeListenerCode, methods); + dataSource = new DataSource(realId, constantId, getSource(), compiler, methods); - // handles all of the listener additions + // compile binding - boolean isBinding = dataSource.compile(); + boolean binding = dataSource.compile(); - if (!isBinding) { + if (!binding) { + // free the generated id + bindingHelper.revertSafeId(id.trim()); } // was compiled compiled = true; - if (isBinding && (DataBindingHelper.SHOW_LOG || log.isDebugEnabled())) { - log.info("detect a databinding\n" + this); + if (DataBindingHelper.SHOW_LOG || log.isDebugEnabled()) { + if (binding) { + log.info("detect a databinding : " + this); + } else { + log.info("reject a databinding : " + getSource()); + } } - // update initDataBinding code + // compute initDataBinding code - initDataBinding = getInitDataBindingCode(compiler, dataSource, isBinding); + initDataBinding = getInitDataBindingCode(compiler, dataSource, binding); - // update processDataBinding code + // compute processDataBinding code - processDataBinding = getProcessDataBindingCode(compiler, dataSource, isBinding); + processDataBinding = getProcessDataBindingCode(compiler, dataSource, binding); - return isBinding; + return binding; } protected String getInitDataBindingCode(JAXXCompiler compiler, DataSource dataSource, boolean isBinding) { @@ -265,9 +251,9 @@ String objectCode = dataSource.getObjectCode(); // no need to test objectCode not null if on root object - boolean needTest = objectCode != null && !compiler.getRootObject().getId().equals(objectCode); + boolean needTest = objectCode != null && !objectCode.trim().isEmpty() && !compiler.getRootObject().getId().equals(objectCode + " != null"); if (needTest) { - buffer.append("if (").append(objectCode).append(" != null) {").append(eol); + buffer.append("if (").append(objectCode).append(") {").append(eol); } buffer.append(JavaFileGenerator.indent(getAssignment(), needTest ? 4 : 0, false, eol)); if (needTest) { Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataBindingHelper.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataBindingHelper.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataBindingHelper.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -192,10 +192,9 @@ } /** - * Finalize discovered bindings for the associated compiler. + * Compile all binding discovered previously. * <p/> - * The method will compile all bindings. The one which are not data binding, are just - * process as property set (with the binding assigment) and remove from the binding list. + * If a binding is not a dataBinding, then move it from the list {@link #dataBindings} to {@link #simpleBindings}. */ public void finalizeBindings() { Added: trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataListener.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataListener.java (rev 0) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataListener.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -0,0 +1,66 @@ +package jaxx.compiler.binding; + +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; + +/** + * Created: 5 déc. 2009 + * + * @author Tony Chemit <chemit@codelutin.com> Copyright Code Lutin + * @version $Revision$ + * <p/> + * Mise a jour: $Date$ par : + * $Author: tchemit $ + */ +public class DataListener { + + /** + * Unique id of the data listener (should be something like objectId.propertyName + */ + protected final String symbol; + /** + * the nullity test to do before to add or remove the listener + */ + protected final String objectCode; + /** + * code of the add listener + */ + protected final String addListenerCode; + /** + * code of the remove listener + */ + protected final String removeListenerCode; + + public DataListener(String symbol, String objectCode, String addListenerCode, String removeListenerCode) { + this.symbol = symbol; + this.objectCode = objectCode; + this.addListenerCode = addListenerCode; + this.removeListenerCode = removeListenerCode; + } + + public String getSymbol() { + return symbol; + } + + public String getObjectCode() { + return objectCode; + } + + public String getAddListenerCode() { + return addListenerCode; + } + + public String getRemoveListenerCode() { + return removeListenerCode; + } + + @Override + public String toString() { + ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE); + b.append("symbol", symbol); + b.append("objectCode", objectCode); + b.append("addListenerCode", addListenerCode.trim()); + b.append("removeListenerCode", removeListenerCode.trim()); + return b.toString(); + } +} Property changes on: trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataListener.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataSource.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataSource.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataSource.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -25,7 +25,6 @@ import jaxx.compiler.JAXXCompiler; import jaxx.compiler.UnsupportedAttributeException; import jaxx.compiler.java.JavaArgument; -import jaxx.compiler.java.JavaFileGenerator; import jaxx.compiler.java.JavaMethod; import jaxx.compiler.java.parser.JavaParser; import jaxx.compiler.java.parser.JavaParserConstants; @@ -46,12 +45,9 @@ import org.apache.commons.logging.LogFactory; import java.beans.Introspector; -import java.beans.PropertyChangeListener; import java.io.StringReader; import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; /** * Represents a Java expression which fires a <code>PropertyChangeEvent</code> when it can be @@ -89,18 +85,10 @@ */ private final JAXXCompiler compiler; /** - * List of symbols which this data source expression depends on. + * List of detected tracker (if none found, it is not a data binding) */ - private final List<String> dependencySymbols = new ArrayList<String>(); + private final List<DataListener> trackers; /** - * code to put in applyDataBinding method on generated java file - */ - private final StringBuffer addListenerCode; - /** - * code to put in removeDataBinding method on generated java file - */ - private final StringBuffer removeListenerCode; - /** * the delegate of property to be required */ private String objectCode; @@ -111,38 +99,39 @@ * Creates a new data source. After creating a <code>DataSource</code>, use {@link #compile()} * to cause it to function at runtime. * - * @param id the DataSource's id - * @param constantId the DataSource constant id - * @param source the Java source code for the data source expression - * @param compiler the current <code>JAXXCompiler</code> - * @param addListenerCode where to push add code - * @param removeListenerCode where to push remove code - * @param methods where to store extra method to add to binding + * @param id the DataSource's id + * @param constantId the DataSource constant id + * @param source the Java source code for the data source expression + * @param compiler the current <code>JAXXCompiler</code> + * @param methods where to store extra method to add to binding */ - public DataSource(String id, String constantId, String source, JAXXCompiler compiler, StringBuffer addListenerCode, StringBuffer removeListenerCode, List<JavaMethod> methods) { + public DataSource(String id, String constantId, String source, JAXXCompiler compiler, List<JavaMethod> methods) { this.id = id; this.constantId = constantId; this.source = source; this.compiler = compiler; - this.addListenerCode = addListenerCode; - this.removeListenerCode = removeListenerCode; this.methods = methods; + this.trackers = new ArrayList<DataListener>(); } public String getObjectCode() { return objectCode; } + public DataListener[] getTrackers() { + return trackers.toArray(new DataListener[trackers.size()]); + } + @Override public String toString() { ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE); b.append("source:id", id); b.append("source:source", source); - b.append("source:objectCode", objectCode); - if (dependencySymbols != null && !dependencySymbols.isEmpty()) { - b.append("source:dependencySymbols", dependencySymbols.size()); - for (String d : dependencySymbols) { - b.append("source:depencendy ", d); + b.append("source:objectCode", getObjectCode()); + if (!trackers.isEmpty()) { + b.append("source:trackers", trackers.size()); + for (DataListener d : trackers) { + b.append("source:tracker", d); } } return b.toString(); @@ -163,22 +152,70 @@ protected boolean compile() throws CompilerException, IllegalStateException { if (DataBindingHelper.SHOW_LOG || log.isDebugEnabled()) { - log.debug("try to compile dataSource\n" + this); + log.info("======= Start compile of " + source); } JavaParser p = new JavaParser(new StringReader(source)); + + // detect all expressions to treate + Map<SimpleNode, List<SimpleNode>> expressions = new LinkedHashMap<SimpleNode, List<SimpleNode>>(); + Map<SimpleNode, List<SimpleNode>> castsExpressions = new LinkedHashMap<SimpleNode, List<SimpleNode>>(); + List<SimpleNode> literalExpressions = new ArrayList<SimpleNode>(); while (!p.Line()) { SimpleNode node = p.popNode(); - if (log.isDebugEnabled()) { - log.debug("will scan node " + node.getText()); + if (log.isTraceEnabled()) { + log.trace("will scan node " + node.getText()); } + JavaParserUtil.getExpressions(node, expressions, literalExpressions, castsExpressions); + } + + // remove literal expressions + + JavaParserUtil.removeLiteralExpressions(expressions, literalExpressions); + literalExpressions.clear(); + + // remove expressions with dependencies + + JavaParserUtil.removeNoneStandaloneExpressions(expressions, castsExpressions); + + // scan accepted expressions to detect dependencies and track listeners + + for (SimpleNode node : expressions.keySet()) { + if (DataBindingHelper.SHOW_LOG || log.isDebugEnabled()) { + log.info("Will parse expression " + node.getText()); + } scanNode(node); } + if (log.isDebugEnabled()) { - log.debug("dependencySymbols=" + dependencySymbols); + log.debug("trackers=" + trackers); } - boolean isBinding = !dependencySymbols.isEmpty(); + boolean isBinding = !trackers.isEmpty(); + if (isBinding) { + Set<String> result = JavaParserUtil.getRequired(expressions.keySet(), castsExpressions); + + if (result == null || result.isEmpty()) { + + // no requirements + + this.objectCode = ""; + } else { + + // build the fully test from requirements + + StringBuilder buffer = new StringBuilder(); + + Iterator<String> itr = result.iterator(); + buffer.append(itr.next()).append(" != null"); + while (itr.hasNext()) { + buffer.append(" && ").append(itr.next()).append(" != null"); + } + this.objectCode = buffer.toString().trim(); + } + } + castsExpressions.clear(); + expressions.clear(); return isBinding; } @@ -234,8 +271,8 @@ * @return the class descriptor of the return type or null */ private ClassDescriptor determineExpressionType(SimpleNode expression) { - if (log.isDebugEnabled()) { - log.debug("for expression " + expression.getText()); + if (log.isTraceEnabled()) { + log.trace("for expression " + expression.getText()); } assert expression.getId() == JavaParserTreeConstants.JJTPRIMARYEXPRESSION; SimpleNode prefix = expression.getChild(0); @@ -246,8 +283,8 @@ } else if (type == JavaParserTreeConstants.JJTNAME && expression.jjtGetNumChildren() == 1) { // name with no arguments after it ClassDescriptor classDescriptor = scanCompoundSymbol(prefix.getText().trim(), compiler.getRootObject().getObjectClass(), false); - if (log.isDebugEnabled()) { - log.debug("scanCompoundSymbol result for node " + prefix.getText().trim() + " = " + classDescriptor); + if (log.isTraceEnabled()) { + log.trace("scanCompoundSymbol result for node " + prefix.getText().trim() + " = " + classDescriptor); } prefix.setJavaType(classDescriptor); } @@ -269,8 +306,8 @@ if (suffix.getChild(0).jjtGetNumChildren() == 0) { // at the moment only no-argument methods are trackable contextClass = scanCompoundSymbol(lastNode, contextClass, true); - if (log.isDebugEnabled()) { - log.debug("scanCompoundSymbol result for node " + lastNode + " = " + contextClass); + if (log.isTraceEnabled()) { + log.trace("scanCompoundSymbol result for node " + lastNode + " = " + contextClass); } if (contextClass == null) { return null; @@ -284,15 +321,18 @@ code = compiler.getRootObject().getJavaCode(); } String methodName = lastNode.substring(dotPos + 1).trim(); - if (log.isDebugEnabled()) { - log.debug("try to find type for method " + methodName + ", code : " + code); + if (log.isTraceEnabled()) { + log.trace("try to find type for method " + methodName + ", code : " + code); } try { MethodDescriptor method = contextClass.getMethodDescriptor(methodName); - trackMemberIfPossible(code, contextClass, method.getName(), true); if (log.isDebugEnabled()) { - log.debug("method found = " + method); + log.debug("Will trackMemberIfPossible from method " + method.getName() + " with objectCode = " + code); } + trackMemberIfPossible(code, contextClass, method.getName(), true); + if (log.isTraceEnabled()) { + log.trace("method found = " + method); + } return method.getReturnType(); } catch (NoSuchMethodException e) { // happens for methods defined in the current JAXX file via scripts @@ -308,11 +348,23 @@ if (newMethod != null) { //TC-20091202 must suffix dependency by property, otherwise can not have two bindings // on the same parent... -// addListener(compiler.getRootObject().getId(), - addListener(compiler.getRootObject().getId()+"."+propertyName, - null, - "addPropertyChangeListener(\"" + propertyName + "\", this);" + JAXXCompiler.getLineSeparator(), - "removePropertyChangeListener(\"" + propertyName + "\", this);" + JAXXCompiler.getLineSeparator()); + String bindingId = compiler.getRootObject().getId() + "." + propertyName; + if (log.isDebugEnabled()) { + log.debug("detect a dependency [" + bindingId + "] from a script method " + newMethod.getName() + ", will try to add a listener in method is part of javaBean ..."); + } + // check this is a javaBean + CompiledObject compiledObject = compiler.getObjects().get(propertyName); + if (compiledObject != null && compiledObject.isJavaBean()) { + if (DataBindingHelper.SHOW_LOG || log.isDebugEnabled()) { + log.info("Detect a dependency from a script method '" + newMethod.getName() + "' which reflect a javaBean property " + propertyName); + log.info("Try to add a listener [symbol:" + bindingId + ",objectCode:" + "null" + "]"); + log.debug(">> lastnode = " + lastNode + "(), suffix = " + suffix.getText() + ", expression = " + expression.getText()); + } + addListener(bindingId, + null, + "addPropertyChangeListener(\"" + propertyName + "\", this);" + JAXXCompiler.getLineSeparator(), + "removePropertyChangeListener(\"" + propertyName + "\", this);" + JAXXCompiler.getLineSeparator()); + } contextClass = newMethod.getReturnType(); } } @@ -392,15 +444,15 @@ currentSymbol.append('.'); } currentSymbol.append(tokens[j]); - if (log.isDebugEnabled()) { - log.debug("try to find type for " + currentSymbol); + if (log.isTraceEnabled()) { + log.trace("try to find type for " + currentSymbol); } if (currentSymbol.indexOf(".") == -1) { String memberName = currentSymbol.toString(); CompiledObject object = compiler.getCompiledObject(memberName); if (object != null) { - if (log.isDebugEnabled()) { - log.debug("detected an object " + object); + if (log.isTraceEnabled()) { + log.trace("detected an object " + object); } contextClass = object.getObjectClass(); currentSymbol.setLength(0); @@ -409,6 +461,9 @@ } else { try { FieldDescriptor field = contextClass.getFieldDescriptor(memberName); + if (log.isDebugEnabled()) { + log.debug("Will trackMemberIfPossible from field " + field.getName() + " with objectCode = " + tokensSeenSoFar.toString()); + } trackMemberIfPossible(tokensSeenSoFar.toString(), contextClass, field.getName(), false); try { contextClass = field.getType(); @@ -425,13 +480,10 @@ // still in root context FieldDescriptor newField = compiler.getScriptField(memberName); if (newField != null) { - if (log.isDebugEnabled()) { - log.debug("Detect a field script to use in binding : " + newField); - } contextClass = newField.getType(); - - if (log.isDebugEnabled()) { - log.debug("Add listener for expression " + tokensSeenSoFar.toString()); + if (DataBindingHelper.SHOW_LOG || log.isDebugEnabled()) { + log.info("Detect a dependency from a script field '" + newField + "'"); + log.info("Try to add a listenenr [symbol:" + tokensSeenSoFar.toString() + ",objectCode:" + null + "]"); } String eol = JAXXCompiler.getLineSeparator(); addListener(tokensSeenSoFar.toString(), @@ -482,7 +534,12 @@ DefaultObjectHandler handler = TagManager.getTagHandler(objectClass); try { if (handler.isMemberBound(memberName)) { - addListener(objectCode + "." + memberName + (method ? "()" : ""), + String bindingId = objectCode + "." + memberName + (method ? "()" : ""); + if (DataBindingHelper.SHOW_LOG || log.isDebugEnabled()) { + log.info("Detect a dependency from a event handler for memberName '" + memberName + "' for class " + objectClass); + log.info("Try to add a listenenr [symbol:" + bindingId + ", objectCode:" + objectCode + "]"); + } + addListener(bindingId, objectCode, getAddMemberListenerCode(handler, objectCode, memberName, "this", compiler), getRemoveMemberListenerCode(handler, objectCode, memberName, "this", compiler)); @@ -494,39 +551,28 @@ } private void addListener(String dependencySymbol, String objectCode, String addCode, String removeCode) { - this.objectCode = objectCode; + if (objectCode != null) { + objectCode = objectCode.trim(); + } boolean needTest = objectCode != null && !compiler.getRootObject().getId().equals(objectCode); + if (!needTest) { + objectCode = null; + } if (log.isDebugEnabled()) { log.debug("try to add listener [dependencySymbol:" + dependencySymbol + ", objectCode:" + objectCode + ", addCode:" + addCode + "]"); } - if (!dependencySymbols.contains(dependencySymbol)) { - if (log.isDebugEnabled()) { - log.debug("add [dependencySymbol:" + dependencySymbol + ", objectCode:" + objectCode + "]"); - } - dependencySymbols.add(dependencySymbol); - String eol = JAXXCompiler.getLineSeparator(); - if (dependencySymbols.size() > 1) { - addListenerCode.append(eol); - } - if (needTest) { - addListenerCode.append("if (").append(objectCode).append(" != null) {").append(eol); - } - addListenerCode.append(JavaFileGenerator.indent(addCode, needTest ? 4 : 0, false, eol)); - if (needTest) { - addListenerCode.append(eol).append("}"); - } - if (dependencySymbols.size() > 1) { - removeListenerCode.append(eol); + for (DataListener tracker : trackers) { + if (dependencySymbol.equals(tracker.getSymbol())) { + // listener already existing + return; } - if (needTest) { - removeListenerCode.append("if (").append(objectCode).append(" != null) {").append(eol); - } - removeListenerCode.append(JavaFileGenerator.indent(removeCode, needTest ? 4 : 0, false, eol)); - if (needTest) { - removeListenerCode.append(eol).append("}"); - } } + DataListener tracker = new DataListener(dependencySymbol, objectCode, addCode, removeCode); + if (log.isDebugEnabled()) { + log.debug("add tracker " + tracker); + } + trackers.add(tracker); } public boolean hasMethod(String methodName) { @@ -561,76 +607,67 @@ } DefaultObjectHandler.ProxyEventInfo eventInfo = handler.getEventInfo(memberName); -// DefaultObjectHandler.ProxyEventInfo eventInfo = eventInfos != null ? eventInfos.get(memberName) : null; if (eventInfo != null) { // a "proxied" event is one that doesn't fire PropertyChangeEvent, so we need to convert its native event type into PropertyChangeEvents StringBuffer result = new StringBuffer(); String methodName = "$pr" + compiler.getUniqueId(propertyChangeListenerCode.equals("this") ? constantId : propertyChangeListenerCode); -// String methodName = "$pr" + compiler.getUniqueId(propertyChangeListenerCode); boolean methodExists = hasMethod(methodName); -// boolean methodExists = compiler.hasMethod(methodName); ClassDescriptor eventClass = DefaultObjectHandler.getEventClass(eventInfo.getListenerClass()); -// ClassDescriptor eventClass = getEventClass(eventInfo.listenerClass); if (!methodExists) { methods.add(new JavaMethod(Modifier.PUBLIC, "void", methodName, new JavaArgument[]{new JavaArgument(JAXXCompiler.getCanonicalName(eventClass), "event")}, null, "propertyChange(null);", false)); -// compiler.getJavaFile().addMethod(new JavaMethod(Modifier.PUBLIC, "void", methodName, -// new JavaArgument[]{new JavaArgument(JAXXCompiler.getCanonicalName(eventClass), "event")}, null, -// propertyChangeListenerCode + ".propertyChange(null);", false)); } String code = objectCode + (eventInfo.getModelName() != null ? ".get" + StringUtils.capitalize(eventInfo.getModelName()) + "()" : ""); -// String code = objectCode + (eventInfo.modelName != null ? ".get" + StringUtils.capitalize(eventInfo.modelName) + "()" : ""); result.append("$bindingSources.put(\"").append(code).append("\", ").append(code).append(");").append(JAXXCompiler.getLineSeparator()); //TC-20091105 Util.getEventListener is generic, no more need cast and use simple listener name result.append(code).append('.').append(eventInfo.getAddMethod()).append("( Util.getEventListener(").append(eventInfo.getListenerClass().getSimpleName()).append(".class, ").append("this").append(", ").append(TypeManager.getJavaCode(methodName)).append("));"); -// result.append(code).append('.').append(eventInfo.getAddMethod()).append("( Util.getEventListener(").append(eventInfo.getListenerClass().getSimpleName()).append(".class, ").append(compiler.getRootObject().getJavaCode()).append(", ").append(TypeManager.getJavaCode(methodName)).append("));"); -// result.append(code).append('.').append(eventInfo.addMethod).append("( Util.getEventListener(").append(eventInfo.listenerClass.getSimpleName()).append(".class, ").append(compiler.getRootObject().getJavaCode()).append(", ").append(TypeManager.getJavaCode(methodName)).append("));"); result.append(JAXXCompiler.getLineSeparator()); -// if (eventInfo.modelName != null) { if (eventInfo.getModelName() != null) { -// result.append(getAddMemberListenerCode(objectCode, dataBinding, "get" + StringUtils.capitalize(eventInfo.modelName), result.append(getAddMemberListenerCode(handler, objectCode, "get" + StringUtils.capitalize(eventInfo.getModelName()), Util.class.getSimpleName() + ".getDataBindingUpdateListener(" + (compiler.getOutputClassName() + ".this") + ", " + constantId + ")", -// Util.class.getSimpleName() + ".getDataBindingUpdateListener(this , " + dataBinding + ")", -// Util.class.getSimpleName() + ".getDataBindingUpdateListener(this , \"" + dataBinding + "\")", compiler)); } return result.toString(); + } + String propertyName = null; + if (memberName.startsWith("get")) { + propertyName = Introspector.decapitalize(memberName.substring("get".length())); + } else if (memberName.startsWith("is")) { + propertyName = Introspector.decapitalize(memberName.substring("is".length())); } else { - String propertyName = null; - if (memberName.startsWith("get")) { - propertyName = Introspector.decapitalize(memberName.substring("get".length())); - } else if (memberName.startsWith("is")) { - propertyName = Introspector.decapitalize(memberName.substring("is".length())); - } else { - try { - handler.getBeanClass().getFieldDescriptor(memberName); -// getBeanClass().getFieldDescriptor(memberName); - propertyName = memberName; - } catch (NoSuchFieldException e) { - // ignore ? - } + try { + handler.getBeanClass().getFieldDescriptor(memberName); + propertyName = memberName; + } catch (NoSuchFieldException e) { + // ignore ? } - if (propertyName != null) { - //TC-20091026 when on root object, do not prefix with objectCode - String prefix = objectCode.trim() + "."; - if (objectCode.equals(compiler.getRootObject().getJavaCode())) { - prefix = ""; - } - try { - // check for property-specific addPropertyChangeListener method -// getBeanClass().getMethodDescriptor("addPropertyChangeListener", ClassDescriptorLoader.getClassDescriptor(String.class), - handler.getBeanClass().getMethodDescriptor("addPropertyChangeListener", ClassDescriptorLoader.getClassDescriptor(String.class), - ClassDescriptorLoader.getClassDescriptor(PropertyChangeListener.class)); - return prefix + "addPropertyChangeListener(\"" + propertyName + "\", " + propertyChangeListenerCode + ");\n"; - } catch (NoSuchMethodException e) { - // no property-specific method, use general one - return prefix + "addPropertyChangeListener(" + propertyChangeListenerCode + ");\n"; - } + } + if (propertyName != null) { + //TC-20091026 when on root object, do not prefix with objectCode + String prefix = objectCode.trim() + "."; + if (objectCode.equals(compiler.getRootObject().getJavaCode())) { + prefix = ""; } - return null; + //TC-20091203 : always use the property specific method, this is part of the javaBeans 1.1 norm + //TC-20091203 : if developpers do bad, shame on them... + return prefix + "addPropertyChangeListener(\"" + propertyName + "\", " + propertyChangeListenerCode + ");\n"; + +// try { +// // check for property-specific addPropertyChangeListener method +//// getBeanClass().getMethodDescriptor("addPropertyChangeListener", ClassDescriptorLoader.getClassDescriptor(String.class), +// handler.getBeanClass().getMethodDescriptor("addPropertyChangeListener", ClassDescriptorLoader.getClassDescriptor(String.class), +// ClassDescriptorLoader.getClassDescriptor(PropertyChangeListener.class)); +// return prefix + "addPropertyChangeListener(\"" + propertyName + "\", " + propertyChangeListenerCode + ");\n"; +// } catch (NoSuchMethodException e) { +// if (log.isInfoEnabled()) { +// log.info("Could not get named addPropertyChangeListener on class " + handler.getBeanClass()); +// } +// // no property-specific method, use general one +// return prefix + "addPropertyChangeListener(" + propertyChangeListenerCode + ");\n"; +// } } + return null; } public String getRemoveMemberListenerCode(DefaultObjectHandler handler, String objectCode, String memberName, String propertyChangeListenerCode, JAXXCompiler compiler) { @@ -639,81 +676,72 @@ } DefaultObjectHandler.ProxyEventInfo eventInfo = handler.getEventInfo(memberName); -// ProxyEventInfo eventInfo = eventInfos != null ? eventInfos.get(memberName) : null; if (eventInfo != null) { // a "proxied" event is one that doesn't fire PropertyChangeEvent, // so we need to convert its native event type into PropertyChangeEvents StringBuffer result = new StringBuffer(); String methodName = "$pr" + compiler.getUniqueId(propertyChangeListenerCode.equals("this") ? constantId : propertyChangeListenerCode); boolean methodExists = hasMethod(methodName); -// boolean methodExists = compiler.hasMethod(methodName); if (!methodExists) { ClassDescriptor eventClass = DefaultObjectHandler.getEventClass(eventInfo.getListenerClass()); -// ClassDescriptor eventClass = getEventClass(eventInfo.listenerClass); methods.add(new JavaMethod(Modifier.PUBLIC, "void", methodName, new JavaArgument[]{new JavaArgument(JAXXCompiler.getCanonicalName(eventClass), "event")}, null, "propertyChange(null);", false)); -// compiler.getJavaFile().addMethod(new JavaMethod(Modifier.PUBLIC, "void", methodName, -// new JavaArgument[]{new JavaArgument(JAXXCompiler.getCanonicalName(eventClass), "event")}, null, -// propertyChangeListenerCode + ".propertyChange(null);", false)); } try { String modelMemberName = eventInfo.getModelName() != null ? "get" + StringUtils.capitalize(eventInfo.getModelName()) : null; String modelClassName = modelMemberName != null ? handler.getBeanClass().getMethodDescriptor(modelMemberName).getReturnType().getName() : JAXXCompiler.getCanonicalName(handler.getBeanClass()); String code = objectCode + (eventInfo.getModelName() != null ? "." + modelMemberName + "()" : ""); -// String modelMemberName = eventInfo.modelName != null ? "get" + StringUtils.capitalize(eventInfo.modelName) : null; -// String modelClassName = modelMemberName != null ? getBeanClass().getMethodDescriptor(modelMemberName).getReturnType().getName() : JAXXCompiler.getCanonicalName(getBeanClass()); -// String code = objectCode + (eventInfo.modelName != null ? "." + modelMemberName + "()" : ""); String eol = JAXXCompiler.getLineSeparator(); result.append(modelClassName).append(" $target = ((").append(modelClassName).append(") $bindingSources.remove(\"").append(code).append("\"));").append(eol); //TC-20091105 test if $target is not null result.append("if ($target != null) {").append(eol); //TC-20091105 Util.getEventListener is generic, no more need cast and use simple listener name result.append(" $target.").append(eventInfo.getRemoveMethod()).append("( Util.getEventListener(").append(eventInfo.getListenerClass().getSimpleName()).append(".class, ").append("this").append(", ").append(TypeManager.getJavaCode(methodName)).append("));").append(eol); -// result.append(" $target.").append(eventInfo.removeMethod).append("( Util.getEventListener(").append(eventInfo.listenerClass.getSimpleName()).append(".class, ").append(compiler.getRootObject().getJavaCode()).append(", ").append(TypeManager.getJavaCode(methodName)).append("));").append(eol); result.append("}").append(eol); if (eventInfo.getModelName() != null) { result.append(getRemoveMemberListenerCode(handler, objectCode, "get" + StringUtils.capitalize(eventInfo.getModelName()), Util.class.getSimpleName() + ".getDataBindingUpdateListener(" + compiler.getOutputClassName() + ".this, " + constantId + ")", -// Util.class.getSimpleName() + ".getDataBindingUpdateListener(this, \"" + dataBinding + "\")", compiler)); } return result.toString(); } catch (NoSuchMethodException e) { throw new CompilerException("Internal error: " + e); } + } + + String propertyName = null; + if (memberName.startsWith("get")) { + propertyName = Introspector.decapitalize(memberName.substring("get".length())); + } else if (memberName.startsWith("is")) { + propertyName = Introspector.decapitalize(memberName.substring("is".length())); } else { - String propertyName = null; - if (memberName.startsWith("get")) { - propertyName = Introspector.decapitalize(memberName.substring("get".length())); - } else if (memberName.startsWith("is")) { - propertyName = Introspector.decapitalize(memberName.substring("is".length())); - } else { - try { - handler.getBeanClass().getFieldDescriptor(memberName); -// getBeanClass().getFieldDescriptor(memberName); - propertyName = memberName; - } catch (NoSuchFieldException e) { - // ignore ? - } + try { + handler.getBeanClass().getFieldDescriptor(memberName); + propertyName = memberName; + } catch (NoSuchFieldException e) { + // ignore ? } - if (propertyName != null) { - //TC-20091026 when on root object, do not prefix with objectCode - String prefix = objectCode.trim() + "."; - if (objectCode.equals(compiler.getRootObject().getJavaCode())) { - prefix = ""; - } - try { - // check for property-specific removePropertyChangeListener method - handler.getBeanClass().getMethodDescriptor("removePropertyChangeListener", ClassDescriptorLoader.getClassDescriptor(String.class), - ClassDescriptorLoader.getClassDescriptor(PropertyChangeListener.class)); - return prefix + "removePropertyChangeListener(\"" + propertyName + "\", " + propertyChangeListenerCode + ");\n"; - } catch (NoSuchMethodException e) { - // no property-specific method, use general one - return prefix + "removePropertyChangeListener(" + propertyChangeListenerCode + ");\n"; - } - } + } + if (propertyName == null) { return null; } + + String prefix = objectCode.trim() + "."; + if (objectCode.equals(compiler.getRootObject().getJavaCode())) { + prefix = ""; + } + //TC-20091203 : always use the property specific method, this is part of the javaBeans 1.1 norm + //TC-20091203 : if developpers do bad, shame on them... + return prefix + "removePropertyChangeListener(\"" + propertyName + "\", " + propertyChangeListenerCode + ");\n"; +// try { +// // check for property-specific removePropertyChangeListener method +// handler.getBeanClass().getMethodDescriptor("removePropertyChangeListener", ClassDescriptorLoader.getClassDescriptor(String.class), +// ClassDescriptorLoader.getClassDescriptor(PropertyChangeListener.class)); +// return prefix + "removePropertyChangeListener(\"" + propertyName + "\", " + propertyChangeListenerCode + ");\n"; +// } catch (NoSuchMethodException e) { +// // no property-specific method, use general one +// return prefix + "removePropertyChangeListener(" + propertyChangeListenerCode + ");\n"; +// } } } \ No newline at end of file Added: trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DefaultJAXXBindingWriter.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DefaultJAXXBindingWriter.java (rev 0) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/DefaultJAXXBindingWriter.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -0,0 +1,68 @@ +package jaxx.compiler.binding; + +import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.finalizers.DefaultFinalizer; +import jaxx.compiler.java.JavaFileGenerator; +import jaxx.compiler.java.JavaMethod; +import jaxx.runtime.binding.DefaultJAXXBinding; + +import static java.lang.reflect.Modifier.PUBLIC; +import java.util.List; + +/** + * Created: 5 déc. 2009 + * + * @author Tony Chemit <chemit@codelutin.com> Copyright Code Lutin + * @version $Revision: $ + * <p/> + * Mise a jour: $Date: $ par : + * $Author: tchemit $ + */ +public class DefaultJAXXBindingWriter extends AbstractJAXXBindingWriter<DefaultJAXXBinding> { + + public DefaultJAXXBindingWriter() { + super(DefaultJAXXBinding.class); + } + + @Override + public boolean accept(DataBinding binding) { + return true; + } + + @Override + public void write(DataBinding binding, JavaFileGenerator generator, StringBuilder buffer) { + DataListener[] trackers = binding.getTrackers(); + String eol = JAXXCompiler.getLineSeparator(); + + StringBuilder addBuffer = new StringBuilder(); + StringBuilder removeBuffer = new StringBuilder(); + + for (DataListener tracker : trackers) { + boolean needTest = tracker.getObjectCode() != null; + if (needTest) { + addBuffer.append("if (").append(tracker.getObjectCode()).append(" != null) {").append(eol); + removeBuffer.append("if (").append(tracker.getObjectCode()).append(" != null) {").append(eol); + } + addBuffer.append(JavaFileGenerator.indent(tracker.getAddListenerCode(), needTest ? 4 : 0, false, eol)); + removeBuffer.append(JavaFileGenerator.indent(tracker.getRemoveListenerCode(), needTest ? 4 : 0, false, eol)); + if (needTest) { + addBuffer.append(eol).append("}"); + removeBuffer.append(eol).append("}"); + } + addBuffer.append(eol); + removeBuffer.append(eol); + } + + List<JavaMethod> bMethods = binding.getMethods(); + bMethods.add(0, JavaFileGenerator.newMethod(PUBLIC, DefaultFinalizer.TYPE_VOID, DefaultFinalizer.METHOD_NAME_REMOVE_DATA_BINDING, removeBuffer.toString(), true)); + bMethods.add(0, JavaFileGenerator.newMethod(PUBLIC, DefaultFinalizer.TYPE_VOID, DefaultFinalizer.METHOD_NAME_PROCESS_DATA_BINDING, binding.getProcessDataBinding(), true)); + bMethods.add(0, JavaFileGenerator.newMethod(PUBLIC, DefaultFinalizer.TYPE_VOID, DefaultFinalizer.METHOD_NAME_APPLY_DATA_BINDING, addBuffer.toString(), true)); + + writeInvocationMethod(binding, trackers, generator, buffer, bMethods); + } + + @Override + protected String getConstructorParams(DataBinding binding, DataListener[] trackers) { + return "this, " + binding.getConstantId() + ", true"; + } +} Added: trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/JAXXBindingWriter.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/JAXXBindingWriter.java (rev 0) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/JAXXBindingWriter.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -0,0 +1,50 @@ +package jaxx.compiler.binding; + +import jaxx.compiler.java.JavaFileGenerator; +import jaxx.runtime.JAXXBinding; + +/** + * The contract of a writer of {@link jaxx.runtime.JAXXBinding} creation code from a {@link DataBinding}. + * <p/> + * Created: 5 déc. 2009 + * + * @author Tony Chemit <chemit@codelutin.com> Copyright Code Lutin + * @version $Revision: $ + * <p/> + * Mise a jour: $Date: $ par : + * $Author: tchemit $ + */ +public interface JAXXBindingWriter<B extends JAXXBinding> { + + /** + * Test if a binding can be treated by the writer. + * + * @param binding the binding to test + * @return {@code true} if this writer can be used to generate binding creation code, {@code false} otherwise. + */ + boolean accept(DataBinding binding); + + /** + * Test if the writer was at least used once (says that the method + * {@link #write(DataBinding, JavaFileGenerator, StringBuilder)} was at least invoked once). + * + * @return {@code true} if this writer was used + */ + boolean isUsed(); + + /** + * @return the type of {@link JAXXBinding} to generate + */ + Class<B> getType(); + + /** + * Generate the creation code of the given {@code binding} and push it in the given {@code buffer}. + * <p/> + * Note: after beean in this method, the {@link #isUsed()} should always return {@code true}. + * + * @param binding the binding to use + * @param generator common generator to build creation code + * @param buffer where to push creation code + */ + void write(DataBinding binding, JavaFileGenerator generator, StringBuilder buffer); +} Added: trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/JavaParserUtil.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/JavaParserUtil.java (rev 0) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/JavaParserUtil.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -0,0 +1,359 @@ +package jaxx.compiler.binding; + +import jaxx.compiler.java.parser.JavaParserTreeConstants; +import jaxx.compiler.java.parser.SimpleNode; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.beans.Introspector; +import java.util.*; + +/** + * Created: 4 déc. 2009 + * + * @author Tony Chemit <chemit@codelutin.com> Copyright Code Lutin + * @version $Revision$ + * <p/> + * Mise a jour: $Date$ par : + * $Author: tchemit $ + */ +public class JavaParserUtil { + + /** + * Logger + */ + private static final Log log = LogFactory.getLog(JavaParserUtil.class); + + private static final Comparator<String> STRING_LENGTH_COMPARATOR = new Comparator<String>() { + + @Override + public int compare(String o1, String o2) { + return o1.length() - o2.length(); + } + }; + + /** + * Obtain all expressions of a node and store them in {@code store} with their dependencies expressions. + * <p/> + * Also fill the {@code literals} list of literal expressions. + * + * @param node the node to scan + * @param store the store of expressions detected with all the expression which compose the expression (can be empty) + * @param literals the list of literal expressions detected + * @param casts the list of casted expression detected + */ + public static void getExpressions(SimpleNode node, Map<SimpleNode, List<SimpleNode>> store, List<SimpleNode> literals, Map<SimpleNode, List<SimpleNode>> casts) { + + if (node.getId() == JavaParserTreeConstants.JJTMETHODDECLARATION || + node.getId() == JavaParserTreeConstants.JJTFIELDDECLARATION) { + //TODO add all others non intressing type of node to reject directly + return; + } + + if (node.getId() == JavaParserTreeConstants.JJTPRIMARYEXPRESSION) { + // get a primary expression, look for his dependencies + scanForExpressions(node, null, store, literals, casts); + return; + } + + // recurse of childs of node + for (int i = 0, count = node.jjtGetNumChildren(); i < count; i++) { + getExpressions(node.getChild(i), store, literals, casts); + } + + } + + /** + * Remove from expressions store, all literal expressions and dependencies on it. + * + * @param store the store of expressions with theirs dependencies + * @param literalExpressions the unvierse of literal expressions + */ + public static void removeLiteralExpressions(Map<SimpleNode, List<SimpleNode>> store, List<SimpleNode> literalExpressions) { + for (SimpleNode n : literalExpressions) { + + // on supprime toutes les dependences sur les expression literales + // car on en a pas besoin pour decouvrir les expressions qui peuvent etre nulles... + + if (log.isDebugEnabled()) { + log.debug("Reject literal expression " + n.getText()); + } + for (List<SimpleNode> dependencies : store.values()) { + dependencies.remove(n); + } + store.remove(n); + } + } + + /** + * Remove from expressions sotre, all expressions with dependencies. + * + * @param store the store of expressions with their dependencies + * @param castsExpressions list of cast expression to keep + */ + public static void removeNoneStandaloneExpressions(Map<SimpleNode, List<SimpleNode>> store, Map<SimpleNode, List<SimpleNode>> castsExpressions) { + List<SimpleNode> rejectedExpressions = new ArrayList<SimpleNode>(); + + for (Map.Entry<SimpleNode, List<SimpleNode>> e : store.entrySet()) { + + List<SimpleNode> dependencies = e.getValue(); + SimpleNode node = e.getKey(); + if (castsExpressions.containsKey(node)) { + // the expression is part of a cast, need to keep it + continue; + } + if (!dependencies.isEmpty()) { + + // expression with dependencies, don't treate it, but treate all in dependencies :) + rejectedExpressions.add(node); + if (log.isDebugEnabled()) { + log.debug("Reject expression " + node.getText() + " with " + dependencies.size() + " dependencies"); + for (SimpleNode n : dependencies) { + log.debug(" " + n.getText()); + } + } + } + } + + for (SimpleNode node : rejectedExpressions) { + store.remove(node); + } + + rejectedExpressions.clear(); + } + + + public static Set<String> getRequired(Set<SimpleNode> store, Map<SimpleNode, List<SimpleNode>> casts) { + if (store.isEmpty()) { + return null; + } + + Set<SimpleNode> castCodes = new LinkedHashSet<SimpleNode>(); + for (List<SimpleNode> cast : casts.values()) { + for (SimpleNode node : cast) { + castCodes.add(node); + if (log.isDebugEnabled()) { + log.debug("cast = " + node.getText().trim()); + } + } + } + + List<String> result = new ArrayList<String>(); + for (SimpleNode node : store) { + String expression = node.getText().trim(); + if (result.contains(expression)) { + // already treated + continue; + } + for (SimpleNode castCode : castCodes) { + String str = castCode.getText().trim(); + int index = expression.indexOf(str); + if (index > -1) { + // got a cast, replace the cast expression, by the simple expression + // we have (CAST)XXX --> XXX + if (log.isDebugEnabled()) { + log.debug("got a cast in expresion " + expression + " = " + castCode); + } + String tmp = ""; + //FIXME : should check this is a complete cast : could be only a conversion... + if (index > 1) { + tmp = expression.substring(0, index - 1); + } + tmp += ((SimpleNode) castCode.jjtGetChild(1)).getText().trim() + expression.substring(index + str.length() + 1); + if (log.isDebugEnabled()) { + log.debug("REMOVED CAST : " + tmp); + } + expression = tmp; + } + } + if (expression.indexOf(".") == -1) { + // not an expression to keep + // a simple field use like 'isEnabled()' or 'field' + // or a not method invocation + if (log.isDebugEnabled()) { + log.debug("Reject simple expression " + expression); + } + continue; + } + if (expression.indexOf("(") == -1) { + // expression with no called method, probably is a constant + // should test it, but for the moment just limits bindings to interfield expressions : a.b + // is not possible, use a.getB() instead of + if (log.isDebugEnabled()) { + log.debug("Reject constant or static expression " + expression); + } + continue; + } + + if (log.isDebugEnabled()) { + log.debug("Keep expression " + expression); + } + result.add(expression); + } + + if (result.isEmpty()) { + return null; + } + + Collections.sort(result, STRING_LENGTH_COMPARATOR); + if (log.isDebugEnabled()) { + log.debug("======= start with values : " + result); + } + + + Set<String> objectCodes = new LinkedHashSet<String>(); + + for (String expression : result) { + + // test if we have a cast in this expression + + Set<String> tmp = new LinkedHashSet<String>(); + + String[] paths = expression.split("\\s*\\.\\s*"); + if (paths.length < 2) { + // just a simple expression + // TODO Should never come here... + continue; + } + + if (log.isDebugEnabled()) { + log.debug("Expression to treate : " + expression + " :: " + Arrays.toString(paths)); + } + + StringBuilder buffer = new StringBuilder(); + String last = paths[0].trim(); + if (last.indexOf("(") > -1) { + // first path is a method invocation or a cast + // at the moment allow cast only on the first member and do no perform any check + + // must check this is a complete method invocation + String args = getMethodInvocationParameters(last); + if (args == null) { + // this path is not a method invocation + // must break + continue; + } + if (!args.isEmpty()) { + // for the moment, we only accept method with no args + // must break + continue; + } + + } + buffer.append(last); + tmp.add(buffer.toString()); + for (int i = 1, max = paths.length - 1; i < max; i++) { + String s = paths[i].trim(); + String args = getMethodInvocationParameters(s); + if (args == null) { + // this path is not a method invocation + // must break + // if previous + break; + } + if (!args.isEmpty()) { + // for the moment, we only accept method with no args + // must break + break; + } + buffer.append(".").append(s); + last = buffer.toString(); + tmp.add(last); + } + objectCodes.addAll(tmp); + } + + if (log.isDebugEnabled()) { + log.debug("Detected requirements : " + objectCodes); + } + return objectCodes; + } + + public static String getMethodInvocationParameters(String code) { + int openIndex = code.indexOf("("); + int closeIndex = code.lastIndexOf(")"); + if (openIndex > -1 && closeIndex > -1) { + if (closeIndex == openIndex + 1) { + return ""; + } + // missing something + return code.substring(openIndex + 1, closeIndex - 1).trim(); + } + return null; + } + + public static String getPropertyNameFromMethod(String code) { + int openIndex = code.indexOf("("); + if (openIndex != -1) { + code = code.substring(0, openIndex); + } + int index = 3; + if (code.startsWith("is")) { + index = 2; + } + code = code.substring(index); + code = Introspector.decapitalize(code); + return code; + } + + public static void scanForExpressions(SimpleNode node, SimpleNode lastExpressionNode, Map<SimpleNode, List<SimpleNode>> store, List<SimpleNode> literals, Map<SimpleNode, List<SimpleNode>> casts) { + + String nodeExpression = node.getText().trim(); + if (log.isTraceEnabled()) { + log.trace("node " + node.getId() + " nbChilds : " + node.jjtGetNumChildren() + " : " + nodeExpression); + } + if (node.getId() == JavaParserTreeConstants.JJTLITERAL) { + // expression literal qu'on ne veut pas garder ? + if (log.isDebugEnabled()) { + log.debug("detected literal " + nodeExpression + " for last expression " + lastExpressionNode.getText()); + } + literals.add(lastExpressionNode); + return; + } + if (node.getId() == JavaParserTreeConstants.JJTCASTEXPRESSION) { + // expression literal qu'on ne veut pas garder ? + if (log.isDebugEnabled()) { + log.debug("detected cast " + nodeExpression + " for last expression " + lastExpressionNode.getText()); + } + List<SimpleNode> simpleNodeList = casts.get(lastExpressionNode); + if (simpleNodeList == null) { + simpleNodeList = new ArrayList<SimpleNode>(); + casts.put(lastExpressionNode, simpleNodeList); + } + simpleNodeList.add(node); + } + + if (node.getId() == JavaParserTreeConstants.JJTPRIMARYEXPRESSION) { + + if (store.get(node) == null) { + store.put(node, new ArrayList<SimpleNode>()); + } + if (lastExpressionNode == null) { + + // premiere entree dans la methode (detection d'une nouvelle expression) + // rien a faire + + + } else { + + // on vient d'un appel recursif, on ajoute le noeud courant a la liste des expression de l'expression parent + + List<SimpleNode> simpleNodeList = store.get(lastExpressionNode); + if (simpleNodeList == null) { + simpleNodeList = new ArrayList<SimpleNode>(); + store.put(node, simpleNodeList); + } + simpleNodeList.add(node); + } + + // on change la derniere expression rencontree + lastExpressionNode = node; + } + + // on parcours tous les fils du noeud courant + for (int i = 0, count = node.jjtGetNumChildren(); i < count; i++) { + scanForExpressions(node.getChild(i), lastExpressionNode, store, literals, casts); + } + } + +} Property changes on: trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/JavaParserUtil.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/SimpleJAXXObjectBindingWriter.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/SimpleJAXXObjectBindingWriter.java (rev 0) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/binding/SimpleJAXXObjectBindingWriter.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -0,0 +1,69 @@ +package jaxx.compiler.binding; + +import jaxx.compiler.finalizers.DefaultFinalizer; +import jaxx.compiler.java.JavaFileGenerator; +import jaxx.compiler.java.JavaMethod; +import jaxx.runtime.binding.SimpleJAXXObjectBinding; + +import java.lang.reflect.Modifier; +import java.util.List; + +/** + * Created: 5 déc. 2009 + * + * @author Tony Chemit <chemit@codelutin.com> Copyright Code Lutin + * @version $Revision: $ + * <p/> + * Mise a jour: $Date: $ par : + * $Author: tchemit $ + */ +public class SimpleJAXXObjectBindingWriter extends AbstractJAXXBindingWriter<SimpleJAXXObjectBinding> { + + protected boolean used; + + public SimpleJAXXObjectBindingWriter() { + super(SimpleJAXXObjectBinding.class); + } + + @Override + public boolean accept(DataBinding binding) { + DataListener[] trackers = binding.getTrackers(); + if (trackers.length > 0) { + for (DataListener tracker : trackers) { + if (tracker.getObjectCode() != null) { + // tracker must be without any requirement + return false; + } + } + } + return true; + } + + @Override + protected String getConstructorParams(DataBinding binding, DataListener[] trackers) { + + StringBuilder addBuffer = new StringBuilder(); + addBuffer.append("this, ").append(binding.getConstantId()).append(", true"); + + for (DataListener tracker : trackers) { + String symbol = tracker.getSymbol(); + String propertyName = symbol.substring(symbol.indexOf(".") + 1); + if (JavaParserUtil.getMethodInvocationParameters(propertyName) != null) { + // obtain the property name from the method name + propertyName = JavaParserUtil.getPropertyNameFromMethod(propertyName); + } + addBuffer.append(" ,\"").append(propertyName).append("\""); + } + return addBuffer.toString(); + } + + @Override + public void write(DataBinding binding, JavaFileGenerator generator, StringBuilder buffer) { + DataListener[] trackers = binding.getTrackers(); + List<JavaMethod> bMethods = binding.getMethods(); + + bMethods.add(0, JavaFileGenerator.newMethod(Modifier.PUBLIC, DefaultFinalizer.TYPE_VOID, DefaultFinalizer.METHOD_NAME_PROCESS_DATA_BINDING, binding.getProcessDataBinding(), true)); + + writeInvocationMethod(binding, trackers, generator, buffer, bMethods); + } +} \ No newline at end of file Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/decorators/DefaultCompiledObjectDecorator.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/decorators/DefaultCompiledObjectDecorator.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/decorators/DefaultCompiledObjectDecorator.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -53,9 +53,7 @@ int access = id.startsWith("$") ? Modifier.PRIVATE : Modifier.PROTECTED; if (object == root) { javaFile.addSimpleField(JavaFileGenerator.newField(access, className, id, false, "this")); -// javaFile.addField(new JavaField(access, fullClassName, id, false, "this")); } else { - //TC -20081017 can have generic on compiled Object javaFile.addField(JavaFileGenerator.newField(access, JAXXCompiler.getCanonicalName(object), id, object.isOverride()), object.isJavaBean()); } } @@ -85,7 +83,6 @@ } else if (object.getInitializer() != null) { init += object.getInitializer(); } else { - //TC - 20081017 compiledObject can have generics String canonicalName = JAXXCompiler.getCanonicalName(object); init += "new " + canonicalName + "("; String constructorParams = object.getConstructorParams(); @@ -102,30 +99,32 @@ if (initCode != null && initCode.length() > 0) { result.append(initCode); } - //TC-20091025 generate client properties at creation time (not at setup time) - // in some case can save to create a setup method (when there is only client properties - // to store) + + // add client properties addClientProperties(object, result, eol); return result.toString(); } @Override public String createCompleteSetupMethod(JAXXCompiler compiler, CompiledObject object, JavaFile javaFile) { -// public String createCompleteSetupMethod(JAXXCompiler compiler, CompiledObject object, JavaFile javaFile, StringBuffer initDataBindings) { StringBuffer code = new StringBuffer(); String eol = JAXXCompiler.getLineSeparator(); - //TC-20091025 generate client properties at creation time (not at setup time) - // in some case can save to create a setup method (when there is only client properties - // to store) -// addClientProperties(object); - //TC-20091025 only generate the code if not empty if (object.getId().startsWith("$")) { String additionCode = object.getAdditionCode(); + //TC-20091025 only generate the code if not empty if (!additionCode.isEmpty()) { code.append("// inline complete setup of ").append(object.getId()).append(eol); code.append(additionCode); } } else { + //TODO-TC-20091202 should always create the method to make api more consistent ? + //TODO-TC-20091202 While generating, we deal with this case, it seems not sa natural + //TODO-TC-20091202 to NOT having the setup method on each public property ? +// code.append(object.getAdditionMethodName()).append("();").append(eol); +// if (!additionCode.isEmpty()) { +// additionCode = "if (!allComponentsCreated) {" + eol + " return;" + eol + "}" + eol + additionCode; +// } +// javaFile.addMethod(JavaFileGenerator.newMethod(Modifier.PROTECTED, "void", object.getAdditionMethodName(), additionCode, false)); String additionCode = object.getAdditionCode(); if (additionCode.length() > 0) { code.append(object.getAdditionMethodName()).append("();").append(eol); Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/DefaultFinalizer.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/DefaultFinalizer.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/DefaultFinalizer.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -22,6 +22,9 @@ import jaxx.compiler.*; import jaxx.compiler.binding.DataBinding; +import jaxx.compiler.binding.DefaultJAXXBindingWriter; +import jaxx.compiler.binding.JAXXBindingWriter; +import jaxx.compiler.binding.SimpleJAXXObjectBindingWriter; import jaxx.compiler.java.*; import static jaxx.compiler.java.JavaFileGenerator.newField; import static jaxx.compiler.java.JavaFileGenerator.newMethod; @@ -56,86 +59,118 @@ * Logger */ protected static final Log log = LogFactory.getLog(DefaultFinalizer.class); + + private static final String PARAMETER_NAME_$BINDING = "$binding"; + + public static final String FIELD_NAME_$BINDING_SOURCES = "$bindingSources"; + public static final String FIELD_NAME_$OBJECT_MAP = "$objectMap"; + public static final String FIELD_NAME_$ACTIVE_BINDINGS = "$activeBindings"; + public static final String FIELD_NAME_ALL_COMPONENTS_CREATED = "allComponentsCreated"; + public static final String FIELD_NAME_CONTEXT_INITIALIZED = "contextInitialized"; + public static final String FIELD_NAME_$PREVIOUS_VALUES = "$previousValues"; + public static final String FIELD_NAME_$BINDINGS = "$bindings"; + public static final String FIELD_NAME_$PROPERTY_CHANGE_SUPPORT = "$propertyChangeSupport"; + public static final String FIELD_NAME_DELEGATE_CONTEXT = "delegateContext"; + public static final String FIELD_NAME_SERIAL_VERSION_UID = "serialVersionUID"; + public static final String FIELD_NAME_$JAXX_OBJECT_DESCRIPTOR = "$jaxxObjectDescriptor"; + + public static final String METHOD_NAME_$GET_JAXXOBJECT_DESCRIPTOR = "$getJAXXObjectDescriptor"; + public static final String METHOD_NAME_$REGISTER_DEFAULT_BINDINGS = "$registerDefaultBindings"; + public static final String METHOD_NAME_REGISTER_DATA_BINDING = "registerDataBinding"; + public static final String METHOD_NAME_REMOVE_DATA_BINDING = "removeDataBinding"; + public static final String METHOD_NAME_APPLY_DATA_BINDING = "applyDataBinding"; + public static final String METHOD_NAME_PROCESS_DATA_BINDING = "processDataBinding"; + public static final String METHOD_NAME_FIRE_PROPERTY_CHANGE = "firePropertyChange"; + public static final String METHOD_NAME_$GET_PROPERTY_CHANGE_SUPPORT = "$getPropertyChangeSupport"; + public static final String METHOD_NAME_$INITIALIZE = "$initialize"; + public static final String METHOD_NAME_$COMPLETE_SETUP = "$completeSetup"; + public static final String METHOD_NAME_$AFTER_COMPLETE_SETUP = "$afterCompleteSetup"; + + public static final String TYPE_STRING = "String"; + public static final String TYPE_VOID = "void"; + public static final String TYPE_BOOLEAN = "boolean"; + public static final String TYPE_OBJECT = "Object"; + /** * serialVersionUID field */ protected static final JavaField SERIAL_VERSION_UID_FIELD = newField(PRIVATE | STATIC | FINAL, - "long", "serialVersionUID", false, "1L"); + "long", FIELD_NAME_SERIAL_VERSION_UID, false, "1L"); /** - * $activeBindings field + * */ protected static final JavaField ACTIVE_BINDINGS_FIELD = newField(PROTECTED, - "java.util.List<Object>", "$activeBindings", false, "new ArrayList<Object>()"); + "java.util.List<" + TYPE_OBJECT + ">", FIELD_NAME_$ACTIVE_BINDINGS, false, "new ArrayList<" + TYPE_OBJECT + ">()"); /** * */ protected static final JavaField BINDING_SOURCES_FIELD = newField(PROTECTED, - "Map<String, Object>", "$bindingSources", false, "new HashMap<String, Object>()"); + "Map<" + TYPE_STRING + ", " + TYPE_OBJECT + ">", FIELD_NAME_$BINDING_SOURCES, false, "new HashMap<" + TYPE_STRING + ", " + TYPE_OBJECT + ">()"); /** * */ protected static final JavaField OBJECT_MAP_FIELD = newField(PROTECTED, - "Map<String, Object>", "$objectMap", true, "new HashMap<String, Object>()"); + "Map<" + TYPE_STRING + ", " + TYPE_OBJECT + ">", FIELD_NAME_$OBJECT_MAP, true, "new HashMap<" + TYPE_STRING + ", " + TYPE_OBJECT + ">()"); /** * */ protected static final JavaField ALL_COMPONENTS_CREATED_FIELD = newField(PRIVATE, - "boolean", "allComponentsCreated", false); + TYPE_BOOLEAN, FIELD_NAME_ALL_COMPONENTS_CREATED, false); /** * */ protected static final JavaField CONTEXT_INITIALIZED = newField(PRIVATE, - "boolean", "contextInitialized", false, "true"); + TYPE_BOOLEAN, FIELD_NAME_CONTEXT_INITIALIZED, false, "true"); /** * */ protected static final JavaField PREVIOUS_VALUES_FIELD = newField(PROTECTED, - "Map<?,?>", "$previousValues", false, "new java.util.HashMap<Object, Object>()"); + "Map<?,?>", FIELD_NAME_$PREVIOUS_VALUES, false, "new java.util.HashMap<" + TYPE_OBJECT + ", " + TYPE_OBJECT + ">()"); /** * */ - protected static final JavaField BINDINGS_FIELD = newField(PRIVATE | FINAL, - "Map<String, JAXXBinding>", "$bindings", false, "new java.util.TreeMap<String, JAXXBinding>()"); + protected static final JavaField BINDINGS_FIELD = newField(PROTECTED | FINAL, + "Map<" + TYPE_STRING + ", JAXXBinding>", FIELD_NAME_$BINDINGS, false, "new java.util.TreeMap<" + TYPE_STRING + ", JAXXBinding>()"); /** * */ - protected static final JavaField PROPERTY_CHANGE_SUPPORT_FIELD = newField(0, - "PropertyChangeSupport", "$propertyChangeSupport", false); + protected static final JavaField PROPERTY_CHANGE_SUPPORT_FIELD = newField(PROTECTED, + "PropertyChangeSupport", FIELD_NAME_$PROPERTY_CHANGE_SUPPORT, false); /** * */ protected static final JavaMethod GET_CONTEXT_VALUE_METHOD = newMethod(PUBLIC, "<T> T", "getContextValue", - "return delegateContext.getContextValue(clazz, null);", true, + "return " + FIELD_NAME_DELEGATE_CONTEXT + ".getContextValue(clazz, null);", true, new JavaArgument("Class<T>", "clazz")); /** * */ protected static final JavaMethod GET_CONTEXT_VALUE_NAMED_METHOD = newMethod(PUBLIC, "<T> T", "getContextValue", - "return delegateContext.getContextValue(clazz, name);", true, - new JavaArgument("Class<T>", "clazz"), new JavaArgument("String", "name")); + "return " + FIELD_NAME_DELEGATE_CONTEXT + ".getContextValue(clazz, name);", true, + new JavaArgument("Class<T>", "clazz"), new JavaArgument(TYPE_STRING, "name")); /** * */ - protected static final JavaMethod SET_CONTEXT_VALUE_NAMED_METHOD = newMethod(PUBLIC, "<T> void", "setContextValue", - "delegateContext.setContextValue(o, name);", true, - new JavaArgument("T", "o"), new JavaArgument("String", "name")); + protected static final JavaMethod SET_CONTEXT_VALUE_NAMED_METHOD = newMethod(PUBLIC, "<T> " + TYPE_VOID, "setContextValue", + FIELD_NAME_DELEGATE_CONTEXT + ".setContextValue(o, name);", true, + new JavaArgument("T", "o"), new JavaArgument(TYPE_STRING, "name")); /** * */ - protected static final JavaMethod SET_CONTEXT_VALUE_METHOD = newMethod(PUBLIC, "<T> void", "setContextValue", - "delegateContext.setContextValue(o, null);", true, + protected static final JavaMethod SET_CONTEXT_VALUE_METHOD = newMethod(PUBLIC, "<T> " + TYPE_VOID, "setContextValue", + FIELD_NAME_DELEGATE_CONTEXT + ".setContextValue(o, null);", true, new JavaArgument("T", "o")); /** * */ - protected static final JavaMethod REMOVE_CONTEXT_VALUE_NAMED_METHOD = newMethod(PUBLIC, "<T> void", "removeContextValue", - "delegateContext.removeContextValue(clazz, name);", true, - new JavaArgument("Class<T>", "clazz"), new JavaArgument("String", "name")); + protected static final JavaMethod REMOVE_CONTEXT_VALUE_NAMED_METHOD = newMethod(PUBLIC, "<T> " + TYPE_VOID, "removeContextValue", + FIELD_NAME_DELEGATE_CONTEXT + ".removeContextValue(clazz, name);", true, + new JavaArgument("Class<T>", "clazz"), new JavaArgument(TYPE_STRING, "name")); /** * */ - protected static final JavaMethod REMOVE_CONTEXT_VALUE_METHOD = newMethod(PUBLIC, "<T> void", "removeContextValue", - "delegateContext.removeContextValue(clazz, null);", true, + protected static final JavaMethod REMOVE_CONTEXT_VALUE_METHOD = newMethod(PUBLIC, "<T> " + TYPE_VOID, "removeContextValue", + FIELD_NAME_DELEGATE_CONTEXT + ".removeContextValue(clazz, null);", true, new JavaArgument("Class<T>", "clazz")); /** * @@ -152,75 +187,93 @@ /** * */ - protected static final JavaMethod GET_OBJECT_BY_ID_METHOD = newMethod(PUBLIC, "Object", "getObjectById", - "return $objectMap.get(id);", true, - new JavaArgument("String", "id")); + protected static final JavaMethod GET_OBJECT_BY_ID_METHOD = newMethod(PUBLIC, TYPE_OBJECT, "getObjectById", + "return " + FIELD_NAME_$OBJECT_MAP + ".get(id);", true, + new JavaArgument(TYPE_STRING, "id")); /** * */ - protected static final JavaMethod GET_JAXX_OBJECT_DESCRIPTOR_METHOD = newMethod(PUBLIC | STATIC, "JAXXObjectDescriptor", "$getJAXXObjectDescriptor", - "return Util.decodeCompressedJAXXObjectDescriptor($jaxxObjectDescriptor);", false); + protected static final JavaMethod GET_JAXX_OBJECT_DESCRIPTOR_METHOD = newMethod(PUBLIC | STATIC, "JAXXObjectDescriptor", METHOD_NAME_$GET_JAXXOBJECT_DESCRIPTOR, + "return Util.decodeCompressedJAXXObjectDescriptor(" + FIELD_NAME_$JAXX_OBJECT_DESCRIPTOR + ");", false); /** * */ - protected static final JavaMethod PROCESS_DATA_BINDING_METHOD = newMethod(PUBLIC, "void", "processDataBinding", - "processDataBinding(binding, false);", true, - new JavaArgument("String", "binding")); + protected static final JavaMethod PROCESS_DATA_BINDING_METHOD = newMethod(PUBLIC, TYPE_VOID, METHOD_NAME_PROCESS_DATA_BINDING, + METHOD_NAME_PROCESS_DATA_BINDING + "(" + PARAMETER_NAME_$BINDING + ", false);", true, + new JavaArgument(TYPE_STRING, PARAMETER_NAME_$BINDING)); - protected static final JavaMethod REGISTER_DATA_BINDING_METHOD = newMethod(PRIVATE, "void", "registerDataBinding", - "$bindings.put(binding.getId(), binding);\n" + "applyDataBinding(binding.getId());", - false, + /** + * + */ + protected static final JavaMethod REGISTER_DATA_BINDING_METHOD = newMethod(PUBLIC, TYPE_VOID, METHOD_NAME_REGISTER_DATA_BINDING, + FIELD_NAME_$BINDINGS + ".put(binding.getId(), binding);", + true, new JavaArgument(JAXXBinding.class.getSimpleName(), "binding")); /** * */ - protected static final JavaMethod FIRE_PROPERTY_CHANGE_METHOD = newMethod(PUBLIC, "void", "firePropertyChange", - "super.firePropertyChange(propertyName, oldValue, newValue);", true, - new JavaArgument("String", "propertyName"), new JavaArgument("Object", "oldValue"), new JavaArgument("Object", "newValue")); + protected static final JavaMethod GET_DATA_BINDING_METHOD = newMethod(PUBLIC, JAXXBinding.class.getSimpleName() + "[]", "getDataBindings", + "return " + FIELD_NAME_$BINDINGS + ".values().toArray(new " + JAXXBinding.class.getSimpleName() + "[" + FIELD_NAME_$BINDINGS + ".size()]);", + true); + + /** * */ - protected static final JavaMethod FIRE_PROPERTY_CHANGE_NAMED_METHOD = newMethod(PUBLIC, "void", "firePropertyChange", - "$getPropertyChangeSupport().firePropertyChange(propertyName, oldValue, newValue);", true, - new JavaArgument("String", "propertyName"), new JavaArgument("Object", "oldValue"), new JavaArgument("Object", "newValue")); + protected static final JavaMethod FIRE_PROPERTY_CHANGE_METHOD = newMethod(PUBLIC, TYPE_VOID, METHOD_NAME_FIRE_PROPERTY_CHANGE, + "super." + METHOD_NAME_FIRE_PROPERTY_CHANGE + "(propertyName, oldValue, newValue);", true, + new JavaArgument(TYPE_STRING, "propertyName"), new JavaArgument(TYPE_OBJECT, "oldValue"), new JavaArgument(TYPE_OBJECT, "newValue")); /** * */ - protected static final JavaMethod GET_PROPERTY_CHANGE_SUPPORT_METHOD = newMethod(0, "PropertyChangeSupport", "$getPropertyChangeSupport", - "if ($propertyChangeSupport == null)\n" + - " $propertyChangeSupport = new PropertyChangeSupport(this);\n" + - "return $propertyChangeSupport;", false); + protected static final JavaMethod FIRE_PROPERTY_CHANGE_NAMED_METHOD = newMethod(PUBLIC, TYPE_VOID, METHOD_NAME_FIRE_PROPERTY_CHANGE, + METHOD_NAME_$GET_PROPERTY_CHANGE_SUPPORT + "()." + METHOD_NAME_FIRE_PROPERTY_CHANGE + "(propertyName, oldValue, newValue);", true, + new JavaArgument(TYPE_STRING, "propertyName"), new JavaArgument(TYPE_OBJECT, "oldValue"), new JavaArgument(TYPE_OBJECT, "newValue")); /** * */ - protected static final JavaMethod ADD_PROPERTY_CHANGE_SUPPORT_METHOD = newMethod(PUBLIC, "void", "addPropertyChangeListener", - "$getPropertyChangeSupport().addPropertyChangeListener(listener);", true, - new JavaArgument("PropertyChangeListener", "listener")); + protected static final JavaMethod GET_PROPERTY_CHANGE_SUPPORT_METHOD = newMethod(0, PropertyChangeSupport.class.getSimpleName(), METHOD_NAME_$GET_PROPERTY_CHANGE_SUPPORT, + "if (" + FIELD_NAME_$PROPERTY_CHANGE_SUPPORT + " == null)\n" + + " " + FIELD_NAME_$PROPERTY_CHANGE_SUPPORT + " = new PropertyChangeSupport(this);\n" + + "return " + FIELD_NAME_$PROPERTY_CHANGE_SUPPORT + ";", false); /** * */ - protected static final JavaMethod ADD_PROPERTY_CHANGE_SUPPORT_NAMED_METHOD = newMethod(PUBLIC, "void", "addPropertyChangeListener", - "$getPropertyChangeSupport().addPropertyChangeListener(property, listener);", true, - new JavaArgument("String", "property"), new JavaArgument("PropertyChangeListener", "listener")); + protected static final JavaMethod ADD_PROPERTY_CHANGE_SUPPORT_METHOD = newMethod(PUBLIC, TYPE_VOID, "addPropertyChangeListener", + METHOD_NAME_$GET_PROPERTY_CHANGE_SUPPORT + "().addPropertyChangeListener(listener);", true, + new JavaArgument(PropertyChangeListener.class.getSimpleName(), "listener")); /** * */ - protected static final JavaMethod REMOVE_PROPERTY_CHANGE_SUPPORT_METHOD = newMethod(PUBLIC, "void", "removePropertyChangeListener", - "$getPropertyChangeSupport().removePropertyChangeListener(listener);", true, - new JavaArgument("PropertyChangeListener", "listener")); + protected static final JavaMethod ADD_PROPERTY_CHANGE_SUPPORT_NAMED_METHOD = newMethod(PUBLIC, TYPE_VOID, "addPropertyChangeListener", + METHOD_NAME_$GET_PROPERTY_CHANGE_SUPPORT + "().addPropertyChangeListener(property, listener);", true, + new JavaArgument(TYPE_STRING, "property"), new JavaArgument(PropertyChangeListener.class.getSimpleName(), "listener")); /** * */ - protected static final JavaMethod REMOVE_PROPERTY_CHANGE_SUPPORT_NAMED_METHOD = newMethod(PUBLIC, "void", "removePropertyChangeListener", - "$getPropertyChangeSupport().removePropertyChangeListener(property, listener);", true, - new JavaArgument("String", "property"), new JavaArgument("PropertyChangeListener", "listener")); + protected static final JavaMethod REMOVE_PROPERTY_CHANGE_SUPPORT_METHOD = newMethod(PUBLIC, TYPE_VOID, "removePropertyChangeListener", + METHOD_NAME_$GET_PROPERTY_CHANGE_SUPPORT + "().removePropertyChangeListener(listener);", true, + new JavaArgument(PropertyChangeListener.class.getSimpleName(), "listener")); + /** + * + */ + protected static final JavaMethod REMOVE_PROPERTY_CHANGE_SUPPORT_NAMED_METHOD = newMethod(PUBLIC, TYPE_VOID, "removePropertyChangeListener", + METHOD_NAME_$GET_PROPERTY_CHANGE_SUPPORT + "().removePropertyChangeListener(property, listener);", true, + new JavaArgument(TYPE_STRING, "property"), new JavaArgument(PropertyChangeListener.class.getSimpleName(), "listener")); + private static final String PARAMETER_NAME_PARENT_CONTEXT = "parentContext"; + @Override + public boolean accept(JAXXCompiler compiler) { + return true; + } + + @Override public void finalizeCompiler(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className) { String fullClassName = packageName != null ? packageName + "." + className : className; if (root == null) { - throw new CompilerException("root tag must be a class tag"); + throw new CompilerException("root tag can not be null"); } ClassDescriptor superclass = root.getObjectClass(); boolean superclassIsJAXXObject = ClassDescriptorLoader.getClassDescriptor(JAXXObject.class).isAssignableFrom(superclass); @@ -234,14 +287,14 @@ javaFile.setGenericType(compiler.getGenericType()); javaFile.setSuperGenericType(compiler.getSuperGenericType()); - // finalize all objects via their decorator - for (CompiledObject object : compiler.getObjects().values()) { - CompiledObjectDecorator decorator = object.getDecorator(); - decorator.finalizeCompiler(compiler, root, object, javaFile, packageName, className, fullClassName); - } +// // finalize all objects via their decorator +// for (CompiledObject object : compiler.getObjects().values()) { +// CompiledObjectDecorator decorator = object.getDecorator(); +// decorator.finalizeCompiler(compiler, root, object, javaFile, packageName, className, fullClassName); +// } - // compile bindings and fill the initDataBindings field of binding helper - compiler.getBindingHelper().finalizeBindings(); +// // compile bindings and fill the initDataBindings field of binding helper +// compiler.getBindingHelper().finalizeBindings(); if (!superclassIsJAXXObject) { javaFile.addInterface(JAXXObject.class.getSimpleName()); @@ -260,6 +313,7 @@ } javaFile.addImport(JAXXContext.class); javaFile.addImport(JAXXObjectDescriptor.class); + javaFile.addImport(JAXXBinding.class); if (!superclassIsJAXXObject) { // add logger @@ -275,9 +329,16 @@ javaFile.addMethod(GET_OBJECT_BY_ID_METHOD); javaFile.addSimpleField(BINDING_SOURCES_FIELD); javaFile.addSimpleField(ACTIVE_BINDINGS_FIELD); + javaFile.addSimpleField(BINDINGS_FIELD); + javaFile.addMethod(REGISTER_DATA_BINDING_METHOD); + javaFile.addMethod(GET_DATA_BINDING_METHOD); + + javaFile.addMethod(createApplyDataBindingMethod()); + javaFile.addMethod(createProcessDataBindingMethod()); + javaFile.addMethod(createRemoveDataBindingMethod()); + // JAXXContext - javaFile.addField(newField(PROTECTED | FINAL, JAXXContext.class.getSimpleName(), "delegateContext", true, "new " + jaxxContextImplementorClass + "()")); -// javaFile.addField(newField(PROTECTED | FINAL, JAXXContext.class.getName(), "delegateContext", true, "new " + jaxxContextImplementorClass + "(this)")); + javaFile.addField(newField(PROTECTED | FINAL, JAXXContext.class.getSimpleName(), FIELD_NAME_DELEGATE_CONTEXT, true, "new " + jaxxContextImplementorClass + "()")); javaFile.addMethod(SET_CONTEXT_VALUE_METHOD); javaFile.addMethod(SET_CONTEXT_VALUE_NAMED_METHOD); javaFile.addMethod(GET_CONTEXT_VALUE_METHOD); @@ -298,7 +359,7 @@ boolean overrideContextInitialized = false; FieldDescriptor[] scriptFields = compiler.getScriptFields(); for (FieldDescriptor f : scriptFields) { - if ("contextInitialized".equals(f.getName())) { + if (FIELD_NAME_CONTEXT_INITIALIZED.equals(f.getName())) { overrideContextInitialized = true; break; } @@ -354,91 +415,81 @@ javaFile.addMethod(createConstructorWithInitialContext(compiler, className, superclassIsJAXXObject)); } - javaFile.addMethod(createInitializer(compiler)); + DataBinding[] bindings = compiler.getBindingHelper().getDataBindings(); + + int nbBindings = bindings.length; + boolean hasDataBindings = nbBindings > 0; + + javaFile.addMethod(createInitializer(compiler, nbBindings)); javaFile.addMethod(GET_JAXX_OBJECT_DESCRIPTOR_METHOD); javaFile.addBodyCode(compiler.getBodyCode().toString()); - String dataBindingInitNode = null; - String simpleBindingInitNode = null; +// javaFile.addMethod(REGISTER_DATA_BINDING_METHOD); +// javaFile.addMethod(GET_DATA_BINDING_METHOD); - String eol = JAXXCompiler.getLineSeparator(); - JavaFileGenerator generator = new JavaFileGenerator(eol, true); + if (hasDataBindings) { - DataBinding[] bindings; + // create the $registerDefaultBindings method - bindings = compiler.getBindingHelper().getSimpleBindings(); - if (bindings.length > 0) { + javaFile.addMethod(createRegisterDefaultBindingsMethod(compiler)); - // get data binding register code + // add import on each type of JAXXBinding used - StringBuilder initCode = new StringBuilder(); + for (JAXXBindingWriter<?> writer : bindingWriters) { + if (writer.isUsed()) { + compiler.getJavaFile().addImport(writer.getType()); + } + } + // for each binding declare the constant Id + for (DataBinding binding : bindings) { - // ce n'est pas un binding, on enregistre le code d'init (si il existe) + String constantId = binding.getConstantId(); - if (binding.getInitDataBinding() != null) { - initCode.append(binding.getInitDataBinding()); - } - } + // add the data binding constant Id - if (initCode.length() > 0) { - simpleBindingInitNode = "// apply " + bindings.length + " property setters " + eol + initCode.toString().trim(); + compiler.addSimpleField(JavaFileGenerator.newField( + (constantId.startsWith("BINDING_$") ? PRIVATE : PUBLIC) | FINAL | STATIC, + TYPE_STRING, constantId, false, TypeManager.getJavaCode(binding.getRealId()))); } } - bindings = compiler.getBindingHelper().getDataBindings(); + javaFile.addMethod(createCompleteSetupMethod(compiler, javaFile)); +// javaFile.addMethod(createApplyDataBindingMethod(superclassIsJAXXObject, hasDataBindings)); +// javaFile.addMethod(createProcessDataBindingMethod(superclassIsJAXXObject, hasDataBindings)); +// javaFile.addMethod(createRemoveDataBindingMethod(superclassIsJAXXObject, hasDataBindings)); - boolean hasDataBindings = bindings.length > 0; + addEventHandlers(compiler, javaFile); + } - if (hasDataBindings) { + protected static final JAXXBindingWriter[] bindingWriters = new JAXXBindingWriter[]{ + new SimpleJAXXObjectBindingWriter(), + new DefaultJAXXBindingWriter() + }; - javaFile.addImport(JAXXBinding.class); - javaFile.addSimpleField(BINDINGS_FIELD); - javaFile.addMethod(REGISTER_DATA_BINDING_METHOD); + protected JavaMethod createRegisterDefaultBindingsMethod(JAXXCompiler compiler) { + DataBinding[] bindings = compiler.getBindingHelper().getDataBindings(); + StringBuilder initCode = new StringBuilder(); +// if (bindings.legth > 0) { - // get data binding register code + String eol = JAXXCompiler.getLineSeparator(); + JavaFileGenerator generator = new JavaFileGenerator(eol, true); + //TODO use optimized writer for simple cases - StringBuilder initCode = new StringBuilder(); + initCode.append("// register ").append(bindings.length).append(" data bindings").append(eol); - for (DataBinding binding : bindings) { + for (DataBinding binding : bindings) { - String constantId = binding.getConstantId(); - - // add the data binding constant Id - - compiler.addSimpleField(new JavaField((constantId.startsWith("BINDING_$") ? PRIVATE : PUBLIC) | FINAL | STATIC, String.class.getSimpleName(), constantId, false, TypeManager.getJavaCode(binding.getRealId()))); - - // register the binding - - List<JavaMethod> bMethods = binding.getMethods(); - - bMethods.add(0, new JavaMethod(PUBLIC, "void", "removeDataBinding", new JavaArgument[0], new String[0], binding.getRemoveListenerCode(), true)); - bMethods.add(0, new JavaMethod(PUBLIC, "void", "processDataBinding", new JavaArgument[0], new String[0], binding.getProcessDataBinding(), true)); - bMethods.add(0, new JavaMethod(PUBLIC, "void", "applyDataBinding", new JavaArgument[0], new String[0], binding.getAddListenerCode(), true)); - - initCode.append("registerDataBinding(new ").append(JAXXBinding.class.getSimpleName()).append("(").append(binding.getConstantId()).append(") {").append(eol); - for (JavaMethod m : bMethods) { - initCode.append(eol).append(JavaFileGenerator.indent(generator.generateMethod(m), 4, false, eol)).append(eol); + for (JAXXBindingWriter<?> writer : bindingWriters) { + if (writer.accept(binding)) { + writer.write(binding, generator, initCode); + break; } - initCode.append("});").append(eol); - - if (binding.getInitDataBinding() != null) { - initCode.append(binding.getInitDataBinding()); - } } - - dataBindingInitNode = "// registers " + bindings.length + " data bindings" + eol + initCode.toString().trim(); } - - javaFile.addMethod(createCompleteSetupMethod(compiler, javaFile, simpleBindingInitNode, dataBindingInitNode)); - - javaFile.addMethod(createApplyDataBindingMethod(superclassIsJAXXObject, hasDataBindings)); - javaFile.addMethod(createProcessDataBindingMethod(superclassIsJAXXObject, hasDataBindings)); - javaFile.addMethod(createRemoveDataBindingMethod(superclassIsJAXXObject, hasDataBindings)); - - addEventHandlers(compiler, javaFile); + return JavaFileGenerator.newMethod(PRIVATE, TYPE_VOID, METHOD_NAME_$REGISTER_DEFAULT_BINDINGS, initCode.toString(), false); } /*---------------------------------------------------------------------------------*/ @@ -462,19 +513,19 @@ int sizeLimit = 65000; // constant strings are limited to 64K, and I'm not brave enough to push right up to the limit if (data.length() < sizeLimit) { - return newField(PRIVATE | STATIC | FINAL, "String", "$jaxxObjectDescriptor", false, TypeManager.getJavaCode(data)); + return newField(PRIVATE | STATIC | FINAL, TYPE_STRING, FIELD_NAME_$JAXX_OBJECT_DESCRIPTOR, false, TypeManager.getJavaCode(data)); } else { StringBuffer initializer = new StringBuffer(); for (int i = 0; i < data.length(); i += sizeLimit) { - String name = "$jaxxObjectDescriptor" + i; - javaFile.addField(new JavaField(PRIVATE | STATIC, "String", name, false, + String name = FIELD_NAME_$JAXX_OBJECT_DESCRIPTOR + i; + javaFile.addField(new JavaField(PRIVATE | STATIC, TYPE_STRING, name, false, TypeManager.getJavaCode(data.substring(i, Math.min(i + sizeLimit, data.length()))))); if (initializer.length() > 0) { initializer.append(" + "); } - initializer.append("String.valueOf(").append(name).append(")"); + initializer.append(TYPE_STRING + ".valueOf(").append(name).append(")"); } - return newField(PRIVATE | STATIC | FINAL, "String", "$jaxxObjectDescriptor", false, initializer.toString()); + return newField(PRIVATE | STATIC | FINAL, TYPE_STRING, FIELD_NAME_$JAXX_OBJECT_DESCRIPTOR, false, initializer.toString()); } } catch (IOException e) { throw new RuntimeException("Internal error: can't-happen error", e); @@ -489,7 +540,7 @@ MethodDescriptor firePropertyChange = null; while (firePropertyChange == null && currentClass != null) { try { - firePropertyChange = currentClass.getDeclaredMethodDescriptor("firePropertyChange", ClassDescriptorLoader.getClassDescriptor(String.class), + firePropertyChange = currentClass.getDeclaredMethodDescriptor(METHOD_NAME_FIRE_PROPERTY_CHANGE, ClassDescriptorLoader.getClassDescriptor(String.class), ClassDescriptorLoader.getClassDescriptor(Object.class), ClassDescriptorLoader.getClassDescriptor(Object.class)); @@ -533,7 +584,7 @@ if (listenerMethod.getParameterTypes().length != 1) { throw new CompilerException("Expected event handler " + listenerMethod.getName() + " of class " + handler.getListenerClass() + " to have exactly one argument"); } - javaFile.addMethod(newMethod(PUBLIC, "void", methodName, handler.getJavaCode(), false, + javaFile.addMethod(newMethod(PUBLIC, TYPE_VOID, methodName, handler.getJavaCode(), false, new JavaArgument(JAXXCompiler.getCanonicalName(listenerMethod.getParameterTypes()[0]), "event"))); } } @@ -551,7 +602,7 @@ code.append(" super();").append(eol); } } - code.append("$initialize();"); + code.append(METHOD_NAME_$INITIALIZE + "();"); code.append(eol); return newMethod(PUBLIC, null, className, code.toString(), false); } @@ -564,36 +615,42 @@ if (superclassIsJAXXObject) { //TODO-TC20091127 This MUST be a convention in JAXX : all specialized constructor must a second //TODO constructor with extra first parameter as parentContext - constructorParams = "parentContext, " + constructorParams; + constructorParams = PARAMETER_NAME_PARENT_CONTEXT + ", " + constructorParams; } code.append(" super(").append(constructorParams).append(");").append(eol); } else { if (superclassIsJAXXObject) { - code.append(" super(parentContext);").append(eol); + code.append(" super(" + PARAMETER_NAME_PARENT_CONTEXT + ");").append(eol); } } if (!superclassIsJAXXObject) { - code.append(Util.class.getSimpleName()).append(".initContext(this, parentContext);"); + code.append(Util.class.getSimpleName()).append(".initContext(this, " + PARAMETER_NAME_PARENT_CONTEXT + ");"); code.append(eol); } - code.append("$initialize();"); + code.append(METHOD_NAME_$INITIALIZE + "();"); code.append(eol); - return newMethod(PUBLIC, null, className, code.toString(), false, new JavaArgument(JAXXContext.class.getSimpleName(), "parentContext")); + return newMethod(PUBLIC, null, className, code.toString(), false, new JavaArgument(JAXXContext.class.getSimpleName(), PARAMETER_NAME_PARENT_CONTEXT)); } - public JavaMethod createInitializer(JAXXCompiler compiler) throws CompilerException { + public JavaMethod createInitializer(JAXXCompiler compiler, int nbBindings) throws CompilerException { String eol = JAXXCompiler.getLineSeparator(); StringBuffer code = new StringBuffer(); CompiledObject root = compiler.getRootObject(); - code.append("if (allComponentsCreated || !contextInitialized) {"); - code.append(eol); - code.append(" return;"); - code.append(eol); - code.append("}"); - code.append(eol); + code.append("if (" + FIELD_NAME_ALL_COMPONENTS_CREATED + " || !" + FIELD_NAME_CONTEXT_INITIALIZED + ") {").append(eol); + code.append(" return;").append(eol); + code.append("}").append(eol); + // register bindings before anything else + if (nbBindings > 0) { + // ajout invocation a la methode d'enregistrement des bindings + code.append("// registers ").append(nbBindings).append(" data bindings").append(eol); + code.append(METHOD_NAME_$REGISTER_DEFAULT_BINDINGS + "();").append(eol); + } +// String dataBindingsCode = createRegisterDefaultBindingsMethod(compiler); +// if (dataBindingsCode != null && !dataBindingsCode.isEmpty()) { +// code.append(dataBindingsCode).append(eol); +// } //TODO-TC20091025 we should remove this if no used anywhere - code.append("$objectMap.put(").append(TypeManager.getJavaCode(root.getId())).append(", this);"); - code.append(eol); + code.append(FIELD_NAME_$OBJECT_MAP + ".put(").append(TypeManager.getJavaCode(root.getId())).append(", this);").append(eol); Iterator<CompiledObject> i = compiler.getObjectCreationOrder(); boolean lastWasMethodCall = false; @@ -611,137 +668,211 @@ if (compiler.getInitializer().length() > 0) { code.append(compiler.getInitializer()); } - code.append("$completeSetup();"); - code.append(eol); - return newMethod(PRIVATE, "void", "$initialize", code.toString(), false); + code.append(METHOD_NAME_$COMPLETE_SETUP + "();").append(eol); + return newMethod(PRIVATE, TYPE_VOID, METHOD_NAME_$INITIALIZE, code.toString(), false); } - protected JavaMethod createCompleteSetupMethod(JAXXCompiler compiler, JavaFile javaFile, String simpleBindingInitNode, String dataBindingInitNode) { + protected JavaMethod createCompleteSetupMethod(JAXXCompiler compiler, JavaFile javaFile) { StringBuffer code = new StringBuffer(); - code.append("allComponentsCreated = true;"); + code.append(FIELD_NAME_ALL_COMPONENTS_CREATED + " = true;"); String eol = JAXXCompiler.getLineSeparator(); code.append(eol); for (CompiledObject object : compiler.getObjects().values()) { CompiledObjectDecorator decorator = object.getDecorator(); code.append(decorator.createCompleteSetupMethod(compiler, object, javaFile)); } - - if (simpleBindingInitNode != null && !simpleBindingInitNode.isEmpty()) { - code.append(simpleBindingInitNode).append(eol); + String simpleBindingsCode = createInitBindingsCode(compiler); + if (simpleBindingsCode != null && !simpleBindingsCode.isEmpty()) { + code.append(simpleBindingsCode).append(eol); } - if (dataBindingInitNode != null && !dataBindingInitNode.isEmpty()) { - code.append(dataBindingInitNode).append(eol); - } - if (compiler.getLateInitializer().length() > 0) { code.append("// late initializer").append(eol); code.append(compiler.getLateInitializer()).append(eol); } //TC-20090313 add an extra method after complete setup - MethodDescriptor method = compiler.getScriptMethod("$afterCompleteSetup"); + MethodDescriptor method = compiler.getScriptMethod(METHOD_NAME_$AFTER_COMPLETE_SETUP); if (method != null) { - code.append("$afterCompleteSetup();").append(eol); + code.append(METHOD_NAME_$AFTER_COMPLETE_SETUP + "();").append(eol); } - return newMethod(PRIVATE, "void", "$completeSetup", code.toString(), false); + return newMethod(PRIVATE, TYPE_VOID, METHOD_NAME_$COMPLETE_SETUP, code.toString(), false); } - protected JavaMethod createApplyDataBindingMethod(boolean superclassIsJAXXObject, boolean haveBinding) { - StringBuilder buffer = new StringBuilder(); + protected String createInitBindingsCode(JAXXCompiler compiler) { String eol = JAXXCompiler.getLineSeparator(); + DataBinding[] bindings; - if (haveBinding) { - if (superclassIsJAXXObject) - buffer.append("if (allComponentsCreated && $bindings.containsKey($binding)) {").append(eol); - else { - buffer.append("if ($bindings.containsKey($binding)) {").append(eol); - } - buffer.append(" $bindings.get($binding).applyDataBinding();").append(eol); - buffer.append("}"); + StringBuilder result = new StringBuilder(); + bindings = compiler.getBindingHelper().getDataBindings(); + if (bindings.length > 0) { + + result.append(eol).append("// apply ").append(bindings.length).append(" data bindings").append(eol); + result.append(Util.class.getSimpleName()).append("." + METHOD_NAME_APPLY_DATA_BINDING + "(this, " + FIELD_NAME_$BINDINGS + ".keySet());").append(eol); + } - if (superclassIsJAXXObject) { + bindings = compiler.getBindingHelper().getSimpleBindings(); + if (bindings.length > 0) { - if (haveBinding) { - buffer.append(" else {").append(eol).append(" "); + StringBuilder initCode = new StringBuilder(); + + for (DataBinding binding : bindings) { + + String binding1 = binding.getInitDataBinding(); + if (binding1 != null && !binding1.trim().isEmpty()) { + initCode.append(binding1); + } } - buffer.append("super.applyDataBinding($binding);").append(eol); - if (haveBinding) { - buffer.append(" return;").append(eol).append("}"); + if (initCode.length() > 0) { + + result.append(eol).append("// apply ").append(bindings.length).append(" property setters").append(eol); + result.append(initCode.toString().trim()); + } - } - buffer.append(eol).append("processDataBinding($binding);"); - return newMethod(PUBLIC, "void", "applyDataBinding", buffer.toString(), true, - new JavaArgument("String", "$binding")); + return result.toString(); } - protected JavaMethod createRemoveDataBindingMethod(boolean superclassIsJAXXObject, boolean haveBinding) { + // protected JavaMethod createApplyDataBindingMethod(boolean superclassIsJAXXObject, boolean haveBinding) { + protected JavaMethod createApplyDataBindingMethod() { StringBuilder buffer = new StringBuilder(); String eol = JAXXCompiler.getLineSeparator(); - if (haveBinding) { +// if (haveBinding) { +// if (superclassIsJAXXObject) + buffer.append("if (" + FIELD_NAME_ALL_COMPONENTS_CREATED + " && " + FIELD_NAME_$BINDINGS + ".containsKey(" + PARAMETER_NAME_$BINDING + ")) {").append(eol); +// else { +// buffer.append("if (" + FIELD_NAME_$BINDINGS + ".containsKey(" + PARAMETER_NAME_$BINDING + ")) {").append(eol); +// } + buffer.append(" " + FIELD_NAME_$BINDINGS + ".get(" + PARAMETER_NAME_$BINDING + ")." + METHOD_NAME_APPLY_DATA_BINDING + "();").append(eol); + buffer.append("}"); - if (superclassIsJAXXObject) { - buffer.append("if (allComponentsCreated && $bindings.containsKey($binding)) {").append(eol); - } else { - buffer.append("if ($bindings.containsKey($binding)) {").append(eol); - } - buffer.append(" $bindings.get($binding).removeDataBinding();").append(eol); - buffer.append("}"); +// } +// if (superclassIsJAXXObject) { +// +// if (haveBinding) { +// buffer.append(" else {").append(eol).append(" "); +// } +// buffer.append("super." + METHOD_NAME_APPLY_DATA_BINDING + "(" + PARAMETER_NAME_$BINDING + ");").append(eol); +// +// if (haveBinding) { +// buffer.append(" return;").append(eol).append("}"); +// } +// +// } +// if (haveBinding) { +// if (superclassIsJAXXObject) +// buffer.append("if (" + FIELD_NAME_ALL_COMPONENTS_CREATED + " && " + FIELD_NAME_$BINDINGS + ".containsKey(" + PARAMETER_NAME_$BINDING + ")) {").append(eol); +// else { +// buffer.append("if (" + FIELD_NAME_$BINDINGS + ".containsKey(" + PARAMETER_NAME_$BINDING + ")) {").append(eol); +// } +// buffer.append(" " + FIELD_NAME_$BINDINGS + ".get(" + PARAMETER_NAME_$BINDING + ")." + METHOD_NAME_APPLY_DATA_BINDING + "();").append(eol); +// buffer.append("}"); +// +// } +// if (superclassIsJAXXObject) { +// +// if (haveBinding) { +// buffer.append(" else {").append(eol).append(" "); +// } +// buffer.append("super." + METHOD_NAME_APPLY_DATA_BINDING + "(" + PARAMETER_NAME_$BINDING + ");").append(eol); +// +// if (haveBinding) { +// buffer.append(" return;").append(eol).append("}"); +// } +// +// } + buffer.append(eol).append(METHOD_NAME_PROCESS_DATA_BINDING + "(" + PARAMETER_NAME_$BINDING + ");"); + return newMethod(PUBLIC, TYPE_VOID, METHOD_NAME_APPLY_DATA_BINDING, buffer.toString(), true, + new JavaArgument(TYPE_STRING, PARAMETER_NAME_$BINDING)); + } - } - if (superclassIsJAXXObject) { + protected JavaMethod createRemoveDataBindingMethod() { +// protected JavaMethod createRemoveDataBindingMethod(boolean superclassIsJAXXObject, boolean haveBinding) { + StringBuilder buffer = new StringBuilder(); + String eol = JAXXCompiler.getLineSeparator(); - if (haveBinding) { - buffer.append(" else {").append(eol).append(" "); - } - buffer.append("super.removeDataBinding($binding);").append(eol); + buffer.append("if (" + FIELD_NAME_ALL_COMPONENTS_CREATED + " && " + FIELD_NAME_$BINDINGS + ".containsKey(" + PARAMETER_NAME_$BINDING + ")) {").append(eol); + buffer.append(" " + FIELD_NAME_$BINDINGS + ".get(" + PARAMETER_NAME_$BINDING + ")." + METHOD_NAME_REMOVE_DATA_BINDING + "();").append(eol); + buffer.append("}"); - if (haveBinding) { - buffer.append("}"); - } - } - return newMethod(PUBLIC, "void", "removeDataBinding", buffer.toString(), true, - new JavaArgument("String", "$binding")); +// if (haveBinding) { +// +// if (superclassIsJAXXObject) { +// buffer.append("if (" + FIELD_NAME_ALL_COMPONENTS_CREATED + " && " + FIELD_NAME_$BINDINGS + ".containsKey(" + PARAMETER_NAME_$BINDING + ")) {").append(eol); +// } else { +// buffer.append("if (" + FIELD_NAME_$BINDINGS + ".containsKey(" + PARAMETER_NAME_$BINDING + ")) {").append(eol); +// } +// buffer.append(" " + FIELD_NAME_$BINDINGS + ".get(" + PARAMETER_NAME_$BINDING + ")." + METHOD_NAME_REMOVE_DATA_BINDING + "();").append(eol); +// buffer.append("}"); +// +// +// } +// if (superclassIsJAXXObject) { +// +// if (haveBinding) { +// buffer.append(" else {").append(eol).append(" "); +// } +// buffer.append("super." + METHOD_NAME_REMOVE_DATA_BINDING + "(" + PARAMETER_NAME_$BINDING + ");").append(eol); +// +// if (haveBinding) { +// buffer.append("}"); +// } +// } + return newMethod(PUBLIC, TYPE_VOID, METHOD_NAME_REMOVE_DATA_BINDING, buffer.toString(), true, + new JavaArgument(TYPE_STRING, PARAMETER_NAME_$BINDING)); } - protected JavaMethod createProcessDataBindingMethod(boolean superclassIsJAXXObject, boolean haveBinding) { + protected JavaMethod createProcessDataBindingMethod() { +// protected JavaMethod createProcessDataBindingMethod(boolean superclassIsJAXXObject, boolean haveBinding) { StringBuffer code = new StringBuffer(); String eol = JAXXCompiler.getLineSeparator(); //boolean superclassIsJAXXObject = ClassDescriptorLoader.getClassDescriptor(JAXXObject.class).isAssignableFrom(compiler.getRootObject().getObjectClass()); // the force parameter forces the update to happen even if it is already in activeBindings. This // is used on superclass invocations b/c by the time the call gets to the superclass, it is already // marked active and would otherwise be skipped - if (haveBinding) { - code.append(" if (!$force && $activeBindings.contains($binding)) { "); - code.append(eol); - code.append(" return;").append(eol); - code.append("}").append(eol); - code.append("$activeBindings.add($binding);").append(eol); - code.append("try {").append(eol); - if (superclassIsJAXXObject) { - code.append(" if (allComponentsCreated && $bindings.containsKey($binding)) {").append(eol); - } else { - code.append(" if ($bindings.containsKey($binding)) {").append(eol); - } - code.append(" $bindings.get($binding).processDataBinding();").append(eol); - code.append(" }"); - if (superclassIsJAXXObject) { - code.append(" else {").append(eol); - code.append(" super.processDataBinding($binding, true);").append(eol); - code.append(" }"); - } - code.append(eol); - code.append("} finally {").append(eol); - code.append(" $activeBindings.remove($binding);").append(eol); - code.append("}").append(eol); - } else if (superclassIsJAXXObject) { - code.append("super.processDataBinding($binding, true);").append(eol); - } - return newMethod(PUBLIC, "void", "processDataBinding", code.toString(), superclassIsJAXXObject, - new JavaArgument("String", "$binding"), new JavaArgument("boolean", "$force")); + + code.append(" if (!$force && " + FIELD_NAME_$ACTIVE_BINDINGS + ".contains(" + PARAMETER_NAME_$BINDING + ")) { ").append(eol); + code.append(" return;").append(eol); + code.append("}").append(eol); + code.append(FIELD_NAME_$ACTIVE_BINDINGS + ".add(" + PARAMETER_NAME_$BINDING + ");").append(eol); + code.append("try {").append(eol); + code.append(" if (" + FIELD_NAME_ALL_COMPONENTS_CREATED + " && " + FIELD_NAME_$BINDINGS + ".containsKey(" + PARAMETER_NAME_$BINDING + ")) {").append(eol); + code.append(" " + FIELD_NAME_$BINDINGS + ".get(" + PARAMETER_NAME_$BINDING + ")." + METHOD_NAME_PROCESS_DATA_BINDING + "();").append(eol); + code.append(" }").append(eol); + code.append("} finally {").append(eol); + code.append(" " + FIELD_NAME_$ACTIVE_BINDINGS + ".remove(" + PARAMETER_NAME_$BINDING + ");").append(eol); + code.append("}").append(eol); + +// if (haveBinding) { +// code.append(" if (!$force && " + FIELD_NAME_$ACTIVE_BINDINGS + ".contains(" + PARAMETER_NAME_$BINDING + ")) { "); +// code.append(eol); +// code.append(" return;").append(eol); +// code.append("}").append(eol); +// code.append(FIELD_NAME_$ACTIVE_BINDINGS + ".add(" + PARAMETER_NAME_$BINDING + ");").append(eol); +// code.append("try {").append(eol); +// if (superclassIsJAXXObject) { +// code.append(" if (" + FIELD_NAME_ALL_COMPONENTS_CREATED + " && " + FIELD_NAME_$BINDINGS + ".containsKey(" + PARAMETER_NAME_$BINDING + ")) {").append(eol); +// } else { +// code.append(" if (" + FIELD_NAME_$BINDINGS + ".containsKey(" + PARAMETER_NAME_$BINDING + ")) {").append(eol); +// } +// code.append(" " + FIELD_NAME_$BINDINGS + ".get(" + PARAMETER_NAME_$BINDING + ")." + METHOD_NAME_PROCESS_DATA_BINDING + "();").append(eol); +// code.append(" }"); +// if (superclassIsJAXXObject) { +// code.append(" else {").append(eol); +// code.append(" super." + METHOD_NAME_PROCESS_DATA_BINDING + "(" + PARAMETER_NAME_$BINDING + ", true);").append(eol); +// code.append(" }"); +// } +// code.append(eol); +// code.append("} finally {").append(eol); +// code.append(" " + FIELD_NAME_$ACTIVE_BINDINGS + ".remove(" + PARAMETER_NAME_$BINDING + ");").append(eol); +// code.append("}").append(eol); +// } else if (superclassIsJAXXObject) { +// code.append("super." + METHOD_NAME_PROCESS_DATA_BINDING + "(" + PARAMETER_NAME_$BINDING + ", true);").append(eol); +// } + return newMethod(PUBLIC, TYPE_VOID, METHOD_NAME_PROCESS_DATA_BINDING, code.toString(), true, + new JavaArgument(TYPE_STRING, PARAMETER_NAME_$BINDING), new JavaArgument(TYPE_BOOLEAN, "$force")); } } Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/SwingFinalizer.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/SwingFinalizer.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/SwingFinalizer.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -20,10 +20,12 @@ */ package jaxx.compiler.finalizers; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.JAXXCompilerFinalizer; import jaxx.compiler.java.JavaArgument; import jaxx.compiler.java.JavaFile; import jaxx.compiler.java.JavaFileGenerator; -import jaxx.compiler.*; import jaxx.compiler.reflect.ClassDescriptorLoader; import jaxx.runtime.swing.Application; @@ -33,14 +35,19 @@ public class SwingFinalizer implements JAXXCompilerFinalizer { @Override + public boolean accept(JAXXCompiler compiler) { + //TODO Should check root object is a component + return true; + } + + @Override public void finalizeCompiler(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className) { } @Override public void prepareJavaFile(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className) throws ClassNotFoundException { - if (ClassDescriptorLoader.getClassDescriptor(Application.class.getName()).isAssignableFrom(root.getObjectClass()) && !compiler.isMainDeclared()) { - // TODO: check for existing main method first + if (!compiler.isMainDeclared() && ClassDescriptorLoader.getClassDescriptor(Application.class.getName()).isAssignableFrom(root.getObjectClass())) { javaFile.addMethod(JavaFileGenerator.newMethod( Modifier.PUBLIC | Modifier.STATIC, "void", Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/ValidatorFinalizer.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/ValidatorFinalizer.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/ValidatorFinalizer.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -20,34 +20,42 @@ */ package jaxx.compiler.finalizers; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.CompiledObject.ChildRef; +import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.JAXXCompilerFinalizer; import jaxx.compiler.java.JavaArgument; import jaxx.compiler.java.JavaField; import jaxx.compiler.java.JavaFile; import jaxx.compiler.java.JavaFileGenerator; -import jaxx.compiler.*; -import jaxx.compiler.CompiledObject.ChildRef; import jaxx.compiler.reflect.ClassDescriptor; import jaxx.compiler.reflect.ClassDescriptorLoader; import jaxx.compiler.tags.validator.BeanValidatorHandler; import jaxx.compiler.tags.validator.BeanValidatorHandler.CompiledBeanValidator; +import jaxx.compiler.types.TypeManager; +import jaxx.runtime.SwingUtil; import java.util.List; -import jaxx.compiler.types.TypeManager; -import jaxx.runtime.SwingUtil; - -/** @author chemit */ +/** + * @author chemit + */ public class ValidatorFinalizer implements JAXXCompilerFinalizer { protected static final JavaField VALIDATOR_IDS_FIELD = JavaFileGenerator.newField(java.lang.reflect.Modifier.PROTECTED, "java.util.List<String>", "validatorIds", true, "new ArrayList<String>()"); @Override + public boolean accept(JAXXCompiler compiler) { + return BeanValidatorHandler.hasValidator(compiler); + } + + @Override public void finalizeCompiler(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className) { - if (!BeanValidatorHandler.hasValidator(compiler)) { - return; - } +// if (!BeanValidatorHandler.hasValidator(compiler)) { +// return; +// } for (CompiledObject object : compiler.getObjects().values()) { List<ChildRef> childs = object.getChilds(); @@ -65,27 +73,26 @@ } } String eol = JAXXCompiler.getLineSeparator(); + StringBuilder builder = new StringBuilder(); // register validator - compiler.appendLateInitializer("// validator setup" + eol); - for (CompiledBeanValidator validator : BeanValidatorHandler.getValidators(compiler)) { + List<CompiledBeanValidator> validators = BeanValidatorHandler.getValidators(compiler); + builder.append("// register ").append(validators.size()).append(" validator(s)").append(eol); + for (CompiledBeanValidator validator : validators) { String id = TypeManager.getJavaCode(validator.getId()); - compiler.appendLateInitializer("validatorIds.add(" + id + ");"); - compiler.appendLateInitializer(eol); - compiler.appendLateInitializer("getValidator(" + id + ").installUIs();"); - compiler.appendLateInitializer(eol); - compiler.appendLateInitializer("getValidator(" + id + ").reloadBean();"); + builder.append("validatorIds.add(").append(id).append(");").append(eol); + builder.append("getValidator(").append(id).append(").installUIs();").append(eol); + builder.append("getValidator(").append(id).append(").reloadBean();").append(eol); //compiler.appendLateInitializer("getValidator(" + id + ").validate();"); - compiler.appendLateInitializer(eol); } - compiler.appendLateInitializer("validatorIds = java.util.Collections.unmodifiableList(validatorIds);"); - compiler.appendLateInitializer(eol); + builder.append("validatorIds = java.util.Collections.unmodifiableList(validatorIds);").append(eol); + compiler.appendLateInitializer(builder.toString()); } @Override public void prepareJavaFile(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className) throws ClassNotFoundException { - if (!BeanValidatorHandler.hasValidator(compiler)) { - return; - } +// if (!BeanValidatorHandler.hasValidator(compiler)) { +// return; +// } Class<?> validatorClass = compiler.getConfiguration().getValidatorClass(); String validatorFQN = validatorClass.getName(); javaFile.addImport(validatorFQN); @@ -93,15 +100,16 @@ //TODO use the specific JAXXValidator interface (swing, gwt,...) Class<?> validatorInterface = jaxx.runtime.JAXXValidator.class; - if (javaFile.isSuperclassIsJAXXObject()) { - ClassDescriptor superClass = ClassDescriptorLoader.getClassDescriptor(javaFile.getSuperClass()); - boolean parentIsValidator = ClassDescriptorLoader.getClassDescriptor(validatorInterface).isAssignableFrom(superClass); + //TC-20091202 : pass this test if we want to interact with non generated code ? +// if (javaFile.isSuperclassIsJAXXObject()) { + ClassDescriptor superClass = ClassDescriptorLoader.getClassDescriptor(javaFile.getSuperClass()); + boolean parentIsValidator = ClassDescriptorLoader.getClassDescriptor(validatorInterface).isAssignableFrom(superClass); - if (parentIsValidator) { - // nothing to generate (use the parent directly) - return; - } + if (parentIsValidator) { + // nothing to generate (use the parent directly) + return; } +// } // add JAXXValidator interface javaFile.addInterface(JAXXCompiler.getCanonicalName(validatorInterface)); Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaElement.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaElement.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaElement.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -21,6 +21,9 @@ package jaxx.compiler.java; import java.lang.reflect.Modifier; +import java.util.Comparator; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Base Java element @@ -62,36 +65,35 @@ } } -// public final String getLineSeparator() { -// if (lineSeparator == null) { -// lineSeparator = JAXXCompiler.getLineSeparator(); -// } -// return lineSeparator; -// } -// -// public static String addIndentation(String source, int indentation, String lineSeparator) { -// return indent(source, indentation, false, lineSeparator); -// } -// -// public static String setIndentation(String source, int indentation, String lineSeparator) { -// return indent(source, indentation, true, lineSeparator); -// } -// -// public static String indent(String source, int indentation, boolean trim, String lineSeparator) { -// if (trim) { -// source = source.trim(); -// } -// char[] spaces = new char[indentation]; -// Arrays.fill(spaces, ' '); -// StringBuffer result = new StringBuffer(); -// String[] lines = source.split(System.getProperty("line.separator") + "|\n"); -// for (int i = 0; i < lines.length; i++) { -// if (i > 0) { -// result.append(lineSeparator); -// } -// result.append(spaces); -// result.append(trim ? lines[i].trim() : lines[i]); -// } -// return result.toString(); -// } + public static final Comparator<JavaElement> JavaElementComparator = new Comparator<JavaElement>() { + + final Pattern NAME_PATTERN = Pattern.compile("(.+)([0-9]+)"); + + @Override + public int compare(JavaElement o1, JavaElement o2) { + + String n1 = o1.getName(); + String n2 = o2.getName(); + + Matcher matcher1 = NAME_PATTERN.matcher(n1); + Matcher matcher2 = NAME_PATTERN.matcher(n2); + if (matcher1.matches() && matcher2.matches()) { + // les deux noms finissent par un nombre + String p1 = matcher1.group(1); + String p2 = matcher1.group(2); + int i = p1.compareTo(p2); + if (i != 0) { + // on est sur des noms de prefix différents, donc pas de tri sur les suffixes + return i; + } + // les deux noms doivent être triés sur les suffixes entiers + int i1 = Integer.valueOf(matcher1.group(2)); + int i2 = Integer.valueOf(matcher2.group(2)); + return i1 - i2; + } + + // les deux noms sont simplement comparé en alpha + return n1.compareTo(n2); + } + }; } Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaField.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaField.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaField.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -21,9 +21,7 @@ package jaxx.compiler.java; import java.lang.reflect.Modifier; -import java.util.Comparator; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.util.*; /** * Represents a field in a Java source file being generated for output. <code>JavaFields</code> are created @@ -32,10 +30,6 @@ public class JavaField extends JavaElement implements Comparable<JavaField> { /** - * Field comparator - */ - static final JavaFieldComparator COMPARATOR = new JavaFieldComparator(); - /** * type of field (fqn) */ private String type; @@ -56,7 +50,7 @@ * @param modifiers the modifier keywords that should appear as part of the field's declaration * @param type the type of the field as it would appear in Java source code * @param name the field's name - * @param override + * @param override flag to add @Override annotation on getter and setter */ public JavaField(int modifiers, String type, String name, boolean override) { this(modifiers, type, name, override, null); @@ -95,9 +89,9 @@ return override; } - public void setOverride(boolean override) { - this.override = override; - } +// public void setOverride(boolean override) { +// this.override = override; +// } public String getInitializer() { return initializer; @@ -105,108 +99,150 @@ @Override public int compareTo(JavaField o) { - return COMPARATOR.compare(this, o); + return JavaElementComparator.compare(this, o); } - static class JavaFieldComparator implements Comparator<JavaField> { + @Override + public String toString() { + return super.toString() + " " + getName() + ", type:" + getType() + ", modifiers:" + Modifier.toString(getModifiers()); + } - @Override - public int compare(JavaField o1, JavaField o2) { - int result; - if ((result = compareStatic(o1, o2)) != 0) { - // les deux fields ne sont pas comparables sur static - return result; + public enum FieldOrder { + + staticsBean(Modifier.STATIC | Modifier.PUBLIC, "Constants for all javaBean properties") { + + @Override + public boolean accept(JavaField field) { + return field.getName().startsWith("PROPERTY_"); +// return field.getName().startsWith("PROPERTY_") && Modifier.isPublic(field.getModifiers()); } - // data sources must be on the last after all other fields - if ((result = compareDataSource(o1, o2)) != 0) { - // les deux fields ne sont pas comparables sur datasource - return result; + }, + + staticsPublicBindings(Modifier.STATIC | Modifier.PUBLIC, "Constants for all public bindings") { + + @Override + public boolean accept(JavaField field) { + return field.getName().startsWith("BINDING_") && Modifier.isPublic(field.getModifiers()); } - // same static - if ((result = compareVisibility(o1, o2)) != 0) { - // les deux fields ne sont pas de la même visibilité - return result; + }, + + staticsPrivateBindings(Modifier.STATIC | Modifier.PRIVATE, "Constants for all none public bindings") { + + @Override + public boolean accept(JavaField field) { + return field.getName().startsWith("BINDING_$") && Modifier.isPrivate(field.getModifiers()); } - // sort on return type - if ((result = compareReturnType(o1, o2)) != 0) { - // les deux fields ne sont pas du même type - return result; + }, + + staticsOthers(Modifier.STATIC, "Other static fields"), + + internalFields(Modifier.PROTECTED | Modifier.PRIVATE, "Internal states") { + + private final List<String> fields = Arrays.asList( + "delegateContext", + "$previousValues", + "$bindingSources", + "$objectMap", + "$activeBindings", + "$bindings", + "$propertyChangeSupport", + "allComponentsCreated", + "contextInitialized"); + + @Override + public boolean accept(JavaField field) { + return fields.contains(field.getName()); } - // same visibility, test name - return compareName(o1.getName(), o2.getName()); + }, + publicFields(Modifier.PUBLIC, "Public components"), + protectedFields(Modifier.PROTECTED, "Protected components"), + privateFields(Modifier.PRIVATE, "Private components"), + otherFields(0, "Other fields") { + @Override + public boolean accept(JavaField field) { + return true; + }}; + private final String header; + private int modifier; + + FieldOrder(int modifier, String header) { + this.header = JavaFileGenerator.getHeader(header); + this.modifier = modifier; } - public int compareStatic(JavaField o1, JavaField o2) { - // first comparator modifiers : static always before none static - if (Modifier.isStatic(o1.getModifiers()) && !Modifier.isStatic(o2.getModifiers())) { - return -1; - } - if (!Modifier.isStatic(o1.getModifiers()) && Modifier.isStatic(o2.getModifiers())) { - return 1; - } - return 0; + public String getHeader() { + return header; } - public int compareReturnType(JavaField o1, JavaField o2) { - return o1.getType().compareTo(o2.getType()); + public boolean accept(JavaField field) { + return true; } - public int compareDataSource(JavaField o1, JavaField o2) { - // first comparator modifiers : static always before none static - if (o1.getName().startsWith("$DataSource") && !o2.getName().startsWith("$DataSource")) { - return 1; - } - if (!o1.getName().startsWith("$DataSource") && o2.getName().startsWith("$DataSource")) { - return -1; - } - return 0; + public boolean accept(int mod) { + return (mod & modifier) != 0; } - public int compareVisibility(JavaField o1, JavaField o2) { - // first comparator modifiers : static always before none static - if (!Modifier.isPublic(o1.getModifiers()) && Modifier.isPublic(o2.getModifiers())) { - return 1; + public boolean accept(int mod, JavaField method) { + return accept(mod) && accept(method); + } + + public static FieldOrder valueOf(JavaField method, int scope) { + for (FieldOrder o : values()) { + if (o.accept(scope, method)) { + return o; + } } - if (Modifier.isPublic(o1.getModifiers()) && !Modifier.isPublic(o2.getModifiers())) { - return -1; - } - if (Modifier.isProtected(o1.getModifiers()) && !Modifier.isProtected(o2.getModifiers())) { - return -1; - } - if (!Modifier.isProtected(o1.getModifiers()) && Modifier.isProtected(o2.getModifiers())) { - return 1; - } - if (Modifier.isPrivate(o1.getModifiers()) && !Modifier.isPrivate(o2.getModifiers())) { - return -1; - } - if (!Modifier.isPrivate(o1.getModifiers()) && Modifier.isPrivate(o2.getModifiers())) { - return 1; - } - return 0; + throw new IllegalArgumentException("could not find a " + FieldOrder.class + " for method " + method); } + } - static final Pattern NAME_PATTERN = Pattern.compile("(.+)([0-9]+)"); + public static EnumMap<FieldOrder, List<JavaField>> getSortedFields(List<JavaField> fields) { - public int compareName(String n1, String n2) { - Matcher matcher1 = NAME_PATTERN.matcher(n1); - Matcher matcher2 = NAME_PATTERN.matcher(n2); - if (matcher1.matches() && matcher2.matches()) { - // les deux noms finissent par un nombre - String p1 = matcher1.group(1); - String p2 = matcher1.group(2); - int i = p1.compareTo(p2); - if (i != 0) { - // on est sur des noms de prefix différents, donc pas de tri sur les suffixes - return i; + EnumMap<FieldOrder, List<JavaField>> result = new EnumMap<FieldOrder, List<JavaField>>(FieldOrder.class); + for (FieldOrder fieldOrder : FieldOrder.values()) { + result.put(fieldOrder, new ArrayList<JavaField>()); + } + + EnumSet<FieldOrder> allConstants = EnumSet.allOf(FieldOrder.class); + List<JavaField> allFields = new ArrayList<JavaField>(fields); + int[] scopes = new int[]{Modifier.STATIC, Modifier.PUBLIC, Modifier.PROTECTED, Modifier.PRIVATE}; + for (int scope : scopes) { + EnumSet<FieldOrder> constants = getFieldOrderScope(allConstants, scope); + + Iterator<JavaField> itMethods = allFields.iterator(); + while (itMethods.hasNext()) { + JavaField method = itMethods.next(); + for (FieldOrder constant : constants) { + if (constant.accept(method.getModifiers(), method)) { + result.get(constant).add(method); + itMethods.remove(); + break; + } } - // les deux noms doivent être triés sur les suffixes entiers - int i1 = Integer.valueOf(matcher1.group(2)); - int i2 = Integer.valueOf(matcher2.group(2)); - return i1 - i2; } + constants.clear(); + } - // les deux noms sont simplement comparé en alpha - return n1.compareTo(n2); + if (!allFields.isEmpty()) { + + // probably package locale fields + result.get(FieldOrder.otherFields).addAll(allFields); } + + for (FieldOrder fieldOrder : FieldOrder.values()) { + // sort fields + java.util.Collections.sort(result.get(fieldOrder)); + } + return result; } + + public static EnumSet<FieldOrder> getFieldOrderScope(EnumSet<FieldOrder> allConstants, int scope) { + EnumSet<FieldOrder> constants = EnumSet.noneOf(FieldOrder.class); + for (FieldOrder order : allConstants) { + if (order.accept(scope)) { + constants.add(order); + } + } + return constants; + } } Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaFile.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaFile.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaFile.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -34,7 +34,6 @@ protected static final String GETTER_PATTERN = "return %1$s;"; protected static final String BOOLEAN_GETTER_PATTERN = "return %1$s !=null && %1$s;"; protected static final String SETTER_PATTERN = "%1$s oldValue = this.%2$s;\nthis.%2$s = newValue;\nfirePropertyChange(%3$s, oldValue, newValue);"; - // protected static final String SETTER_PATTERN = "%1$s oldValue = this.%2$s;\nthis.%2$s = newValue;\nfirePropertyChange(\"%2$s\", oldValue, newValue);"; private Set<String> imports = new HashSet<String>(); private List<JavaField> fields = new ArrayList<JavaField>(); private List<JavaMethod> methods = new ArrayList<JavaMethod>(); @@ -131,7 +130,6 @@ addMethod(new JavaMethod(Modifier.PUBLIC, field.getType(), "is" + capitalizedName, null, null, content, field.isOverride())); } content = String.format(SETTER_PATTERN, field.getType(), id, constantId); -// content = String.format(SETTER_PATTERN, field.getType(), id); JavaArgument arg = new JavaArgument(field.getType(), "newValue"); addMethod(new JavaMethod(Modifier.PUBLIC, "void", "set" + capitalizedName, new JavaArgument[]{arg}, null, content, field.isOverride())); } Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaFileGenerator.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaFileGenerator.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaFileGenerator.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -20,14 +20,16 @@ */ package jaxx.compiler.java; +import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.java.JavaMethod.MethodOrder; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import java.io.PrintWriter; import java.util.Arrays; import java.util.EnumMap; import java.util.List; import java.util.Map.Entry; -import jaxx.compiler.java.JavaMethod.MethodOrder; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; /** * Java file generator. @@ -57,6 +59,23 @@ public static JavaMethod newMethod(int modifiers, String returnType, String name, String initializer, boolean override, JavaArgument... arguments) { return newMethod(modifiers, returnType, name, initializer, override, new String[0], arguments); } + + public static String getHeader(String header) { + String all = "/*-----------------------------------------------------------------------*/"; + int size = header.length(); + if (size % 2 == 0) { + size++; + header = header + " "; + } + int semi = ((all.length() - size) / 2) - 5; + char[] prefix = new char[semi]; + Arrays.fill(prefix, '-'); + + String eol = JAXXCompiler.getLineSeparator(); + + return all + eol + "/*--" + new String(prefix) + " " + header + " " + new String(prefix) + "--*/" + eol + all + eol; + } + /** * End of line */ @@ -75,10 +94,6 @@ this.verbose = verbose && log.isDebugEnabled(); } - public String getEol() { - return eol; - } - public String generateImport(String anImport) { return "import " + anImport + ';' + eol; } @@ -140,15 +155,28 @@ List<JavaField> fields = f.getFields(); if (!fields.isEmpty()) { - java.util.Collections.sort(fields); // sort fields - for (JavaField field : fields) { - if (log.isDebugEnabled()) { - log.debug("generate field " + field); + EnumMap<JavaField.FieldOrder, List<JavaField>> map = JavaField.getSortedFields(fields); + for (Entry<JavaField.FieldOrder, List<JavaField>> entry : map.entrySet()) { + List<JavaField> list = entry.getValue(); + + // sort fields + java.util.Collections.sort(list); + + if (!list.isEmpty()) { + + // add field group header + result.append(eol).append(addIndentation(entry.getKey().getHeader(), 4, eol)).append(eol).append(eol); + + // add all fields of group + for (JavaField method : list) { + String txt = generateField(method); + result.append(addIndentation(txt, 4, eol)).append(eol); + } } - String txt = generateField(field); - result.append(addIndentation(txt, 4, eol)).append(eol); + list.clear(); } + map.clear(); result.append(eol); } @@ -157,14 +185,12 @@ StringBuffer rawBodyCode = f.getRawBodyCode(); if (rawBodyCode.length() > 0) { - result.append(addIndentation("/* begin raw body code */\n", 4, eol)); + result.append(addIndentation(getHeader("Raw body code from script"), 4, eol)).append(eol); String s = rawBodyCode.toString(); if (!s.startsWith(eol)) { result.append(eol); } - result.append(addIndentation(s, 4, eol)).append(eol); - result.append(addIndentation("/* end raw body code */", 4, eol)); - result.append(eol); + result.append(addIndentation(s, 4, eol)).append(eol).append(eol); } // generate inner classes @@ -174,8 +200,7 @@ indentationLevel += 4; try { String txt = generateClass(innerClass); - result.append(addIndentation(txt, 4, eol)); - result.append(eol).append(eol); + result.append(addIndentation(txt, 4, eol)).append(eol).append(eol); } finally { indentationLevel -= 4; } @@ -187,12 +212,17 @@ for (Entry<MethodOrder, List<JavaMethod>> entry : map.entrySet()) { List<JavaMethod> list = entry.getValue(); if (!list.isEmpty()) { - result.append(addIndentation(entry.getKey().getHeader(), 4, eol)); - result.append(eol).append(eol); + + // sort methods + java.util.Collections.sort(list); + + // add method group header + result.append(addIndentation(entry.getKey().getHeader(), 4, eol)).append(eol).append(eol); + + // add all methods of group for (JavaMethod method : list) { String txt = generateMethod(method); - result.append(addIndentation(txt, 4, eol)); - result.append(eol).append(eol); + result.append(addIndentation(txt, 4, eol)).append(eol).append(eol); } } list.clear(); @@ -205,7 +235,9 @@ public String generateField(JavaField f) { if (verbose) { - log.info(f.getName()); + if (log.isDebugEnabled()) { + log.debug(f.getName()); + } } StringBuffer result = new StringBuffer(); result.append(f.getModifiersText()); @@ -235,14 +267,30 @@ result.append('('); JavaArgument[] arguments = m.getArguments(); + // adding arguments + if (arguments != null && arguments.length > 0) { result.append(generateArgument(arguments[0])); for (int i = 1; i < arguments.length; i++) { result.append(", ").append(generateArgument(arguments[i])); } } - result.append(") {"); + result.append(")"); + + // adding exceptions + + String[] exceptions = m.getExceptions(); + if (exceptions != null && exceptions.length > 0) { + result.append(" throws ").append(exceptions[0]); + for (int i = 1; i < exceptions.length; i++) { + result.append(", ").append(exceptions[i]); + } + } + result.append(" {"); result.append(eol); + + // adding body + String body = m.getBody(); if (body != null) { @@ -265,10 +313,6 @@ return indent(source, indentationLevel + indentation, false, lineSeparator); } - public String setIndentation(String source, int indentation, String lineSeparator) { - return indent(source, indentationLevel + indentation, true, lineSeparator); - } - public static String indent(String source, int indentation, boolean trim, String lineSeparator) { if (trim) { source = source.trim(); Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaMethod.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaMethod.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/java/JavaMethod.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -21,13 +21,7 @@ package jaxx.compiler.java; import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.EnumMap; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.List; +import java.util.*; /** * Represents a method in a Java source file being generated for output. <code>JavaMethods</code> are created @@ -38,10 +32,6 @@ public class JavaMethod extends JavaElement implements Comparable<JavaMethod> { /** - * Method comparator - */ - static final JavaMethodComparator COMPARATOR = new JavaMethodComparator(); - /** * return type of the method (null for constructors) */ private String returnType; @@ -74,7 +64,7 @@ * @param arguments the method's arguments * @param exceptions a list of exceptions the methods can throw, as they would be represented in Java source code * @param bodyCode Java source code which should appear in the method body - * @param override flag with {@code true} value when the method overrides (or implements) a super class method + * @param override flag with {@code true} value when the method overrides (or implements) a super class method */ public JavaMethod(int modifiers, String returnType, String name, JavaArgument[] arguments, String[] exceptions, String bodyCode, boolean override) { super(modifiers, name); @@ -116,146 +106,132 @@ return override; } - public void setOverride(boolean override) { - this.override = override; - } - public String getBody() { return body; } @Override public int compareTo(JavaMethod o) { - return COMPARATOR.compare(this, o); + return JavaElementComparator.compare(this, o); } public enum MethodOrder { - statics(Modifier.STATIC, "/*---------------------------------------------------------------------------------*/\n" + - "/*-- Statics methods --------------------------------------------------------------*/\n" + - "/*---------------------------------------------------------------------------------*/") { - }, - constructors(Modifier.PUBLIC, "/*---------------------------------------------------------------------------------*/\n" + - "/*-- Constructors -----------------------------------------------------------------*/\n" + - "/*---------------------------------------------------------------------------------*/") { + statics(Modifier.STATIC, "Statics methods"), + constructors(Modifier.PUBLIC, "Constructors") { + @Override public boolean accept(JavaMethod method) { return method.returnType == null; } }, - JAXXObject(Modifier.PUBLIC, "/*---------------------------------------------------------------------------------*/\n" + - "/*-- JAXXObject implementation ----------------------------------------------------*/\n" + - "/*---------------------------------------------------------------------------------*/") { + JAXXObject(Modifier.PUBLIC, "JAXXObject implementation") { - private List<String> methods = Arrays.asList("applyDataBinding", "firePropertyChange", "getObjectById", "get$objectMap", "processDataBinding", "removeDataBinding"); + private final List<String> methods = Arrays.asList( + "applyDataBinding", + "firePropertyChange", + "getObjectById", + "get$objectMap", + "processDataBinding", + "removeDataBinding", + "registerDataBinding", + "getDataBindings"); @Override public boolean accept(JavaMethod method) { return methods.contains(method.getName()); } }, - JAXXContext(Modifier.PUBLIC, "/*---------------------------------------------------------------------------------*/\n" + - "/*-- JAXXContext implementation ---------------------------------------------------*/\n" + - "/*---------------------------------------------------------------------------------*/") { + JAXXContext(Modifier.PUBLIC, "JAXXContext implementation") { - private List<String> methods = Arrays.asList("getContextValue", "getDelegateContext", "getParentContainer", "removeContextValue", "setContextValue"); + private final List<String> methods = Arrays.asList( + "getContextValue", + "getDelegateContext", + "getParentContainer", + "removeContextValue", + "setContextValue"); @Override public boolean accept(JavaMethod method) { return methods.contains(method.getName()); } }, - JAXXValidation(Modifier.PUBLIC, "/*---------------------------------------------------------------------------------*/\n" + - "/*-- JAXXValidation implementation ------------------------------------------------*/\n" + - "/*---------------------------------------------------------------------------------*/") { + JAXXValidation(Modifier.PUBLIC, "JAXXValidation implementation") { - private List<String> methods = Arrays.asList("getValidator", "getValidatorIds"); + private final List<String> methods = Arrays.asList("getValidator", "getValidatorIds"); @Override public boolean accept(JavaMethod method) { return methods.contains(method.getName()); } }, - events(Modifier.PUBLIC, "/*---------------------------------------------------------------------------------*/\n" + - "/*-- Event methods ----------------------------------------------------------------*/\n" + - "/*---------------------------------------------------------------------------------*/") { + events(Modifier.PUBLIC, "Event methods") { @Override public boolean accept(JavaMethod method) { return (method.getName().startsWith("do") && method.getName().indexOf("__") > -1); } }, - publicGetters(Modifier.PUBLIC, "/*---------------------------------------------------------------------------------*/\n" + - "/*-- public acessor methods -------------------------------------------------------*/\n" + - "/*---------------------------------------------------------------------------------*/") { + publicGetters(Modifier.PUBLIC, "Public acessor methods") { @Override public boolean accept(JavaMethod method) { return (method.getName().startsWith("get") || method.getName().startsWith("is")); } }, - publicSetters(Modifier.PUBLIC, "/*---------------------------------------------------------------------------------*/\n" + - "/*-- public mutator methods -------------------------------------------------------*/\n" + - "/*---------------------------------------------------------------------------------*/") { + publicSetters(Modifier.PUBLIC, "Public mutator methods") { @Override public boolean accept(JavaMethod method) { return (method.getName().startsWith("set")); } }, - otherPublic(Modifier.PUBLIC, "/*---------------------------------------------------------------------------------*/\n" + - "/*-- public mutator methods -------------------------------------------------------*/\n" + - "/*---------------------------------------------------------------------------------*/") { + otherPublic(Modifier.PUBLIC, "Public mutator methods") { @Override public boolean accept(int mod) { return super.accept(mod) && !Modifier.isStatic(mod); } }, - protectedGetters(Modifier.PROTECTED, "/*---------------------------------------------------------------------------------*/\n" + - "/*-- protected acessors methods ---------------------------------------------------*/\n" + - "/*---------------------------------------------------------------------------------*/") { + protectedGetters(Modifier.PROTECTED, "Protected acessors methods") { @Override public boolean accept(JavaMethod method) { return (method.getName().startsWith("get") || method.getName().startsWith("is")); } }, - createMethod(Modifier.PROTECTED | Modifier.PRIVATE, "/*---------------------------------------------------------------------------------*/\n" + - "/*-- ui creation methods ----------------------------------------------------------*/\n" + - "/*---------------------------------------------------------------------------------*/") { - + createMethod(Modifier.PROTECTED | Modifier.PRIVATE, "Components creation methods") { @Override public boolean accept(JavaMethod method) { - return method.getName().startsWith("create") || method.getName().startsWith("add") || - method.getName().equals("$completeSetup") || - method.getName().equals("$registerDataBinding") || - method.getName().equals("$initialize"); + return method.getName().startsWith("create") || method.getName().startsWith("add"); } }, - protecteds(Modifier.PROTECTED, "/*---------------------------------------------------------------------------------*/\n" + - "/*-- Other protected methods ------------------------------------------------------*/\n" + - "/*---------------------------------------------------------------------------------*/") { + internalMethod(Modifier.PRIVATE, "Internal jaxx methods") { + private final List<String> methods = Arrays.asList( + "$completeSetup", + "$registerDefaultBindings", + "$initialize"); + @Override + public boolean accept(JavaMethod method) { + return methods.contains(method.getName()); + } }, - packageLocal(0, "/*---------------------------------------------------------------------------------*/\n" + - "/*-- Package methods --------------------------------------------------------------*/\n" + - "/*---------------------------------------------------------------------------------*/") { + protecteds(Modifier.PROTECTED, "Other protected methods") { + }, + packageLocal(0, "Package methods") { @Override public boolean accept(int mod) { return !Modifier.isStatic(mod) && !Modifier.isPublic(mod) && !Modifier.isProtected(mod); } }, - privates(Modifier.PRIVATE, "/*---------------------------------------------------------------------------------*/\n" + - "/*-- Private methods --------------------------------------------------------------*/\n" + - "/*---------------------------------------------------------------------------------*/") { - }; + privates(Modifier.PRIVATE, "Other private methods"); private final String header; private int modifier; MethodOrder(int modifier, String header) { - this.header = header; + this.header = JavaFileGenerator.getHeader(header); this.modifier = modifier; } @@ -333,64 +309,4 @@ return constants; } - static class JavaMethodComparator implements Comparator<JavaMethod> { - - @Override - public int compare(JavaMethod o1, JavaMethod o2) { - - /*int result; - if ((result = compareStatic(o1, o2)) != 0) { - return result; - } - if ((result = compareConstructor(o1, o2)) != 0) { - return result; - } - if ((result = compareVisibility(o1, o2)) != 0) { - return result; - }*/ - return o1.getName().compareTo(o2.getName()); - } - - public int compareStatic(JavaMethod o1, JavaMethod o2) { - if (Modifier.isStatic(o1.getModifiers()) && !Modifier.isStatic(o2.getModifiers())) { - return -1; - } - if (!Modifier.isStatic(o1.getModifiers()) && Modifier.isStatic(o2.getModifiers())) { - return 1; - } - return 0; - } - - public int compareConstructor(JavaMethod o1, JavaMethod o2) { - if (o1.getReturnType() == null && o2.getReturnType() != null) { - return -1; - } - if (o1.getReturnType() != null && o2.getReturnType() == null) { - return 1; - } - return 0; - } - - public int compareVisibility(JavaMethod o1, JavaMethod o2) { - if (Modifier.isPublic(o1.getModifiers()) && !Modifier.isPublic(o2.getModifiers())) { - return -1; - } - if (!Modifier.isPublic(o1.getModifiers()) && Modifier.isPublic(o2.getModifiers())) { - return 1; - } - if (Modifier.isProtected(o1.getModifiers()) && !Modifier.isProtected(o2.getModifiers())) { - return -1; - } - if (!Modifier.isProtected(o1.getModifiers()) && Modifier.isProtected(o2.getModifiers())) { - return 1; - } - if (Modifier.isPrivate(o1.getModifiers()) && !Modifier.isPrivate(o2.getModifiers())) { - return -1; - } - if (!Modifier.isPrivate(o1.getModifiers()) && Modifier.isPrivate(o2.getModifiers())) { - return 1; - } - return 0; - } - } } Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/reflect/ClassDescriptorLoader.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/reflect/ClassDescriptorLoader.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/reflect/ClassDescriptorLoader.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -26,24 +26,16 @@ import jaxx.compiler.SymbolTable; import jaxx.runtime.JAXXObject; import jaxx.runtime.JAXXObjectDescriptor; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; +import java.io.*; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * Mirrors the class <code>java.lang.ClassLoader</code>. JAXX uses <code>ClassDescriptor</code> instead of <code>Class</code> @@ -52,6 +44,10 @@ * circular dependencies). */ public class ClassDescriptorLoader { + /** + * Logger + */ + private static final Log log = LogFactory.getLog(ClassDescriptorLoader.class); private static Map<String, ClassDescriptor> descriptors = new HashMap<String, ClassDescriptor>(); @@ -112,7 +108,7 @@ if (jaxxLastModified != -1 && JAXXEngine.isRegistred() && JAXXEngine.get().getSymbolTable(className) == null) { jaxxLastModified = -1; // file has been modified, but wasn't included in this - } + } // compilation set so we don't have a symbol table if (javaLastModified != -1 || classLastModified != -1 || jaxxLastModified != -1) { @@ -300,7 +296,6 @@ } try { Method getJAXXObjectDescriptor = jaxxClass.getMethod("$getJAXXObjectDescriptor"); -// Method getJAXXObjectDescriptor = jaxxClass.getMethod("$getJAXXObjectDescriptor", new Class<?>[0]); return (JAXXObjectDescriptor) getJAXXObjectDescriptor.invoke(null); } catch (NoSuchMethodException e) { throw new CompilerException("Expected JAXXObject " + jaxxClass.getName() + " to have a static method named $getJAXXObjectDescriptor"); @@ -313,6 +308,9 @@ private static ClassDescriptor createClassDescriptorFromJavaSource(URL javaSource, ClassLoader classLoader) throws ClassNotFoundException { try { + if (log.isDebugEnabled()) { + log.debug("for source "+javaSource); + } InputStream in = javaSource.openStream(); Reader reader = new InputStreamReader(in, "utf-8"); ClassDescriptor result = JavaFileParser.parseJavaFile(javaSource.toString(), reader, classLoader); @@ -329,6 +327,9 @@ if (symbolTable == null) { throw new CompilerException("Internal error: no symbol table was generated for class '" + className + "'"); } + if (log.isDebugEnabled()) { + log.debug("for compiler " + compiler.getOutputClassName()); + } ClassDescriptor superclass = getClassDescriptor(symbolTable.getSuperclassName(), classLoader); List<MethodDescriptor> publicMethods = symbolTable.getScriptMethods(); List<FieldDescriptor> publicFields = symbolTable.getScriptFields(); @@ -348,11 +349,29 @@ fields.remove(); } } + Set<String> interfaces = new HashSet<String>(); + if (symbolTable.getInterfaces() != null) { + // having interfaces + for (String anInterface : symbolTable.getInterfaces()) { + int genericIndex = anInterface.indexOf("<"); + if (genericIndex > -1) { + // remove generic type + anInterface = anInterface.substring(0, genericIndex); + } + if (log.isDebugEnabled()) { + log.debug("getting interface " + anInterface + " descriptor for class " + className); + } + interfaces.add(anInterface); + ClassDescriptor interfaceclass = getClassDescriptor(anInterface, classLoader); + publicMethods.addAll(Arrays.asList(interfaceclass.getMethodDescriptors())); + publicFields.addAll(Arrays.asList(interfaceclass.getFieldDescriptors())); + } + } publicMethods.addAll(Arrays.asList(superclass.getMethodDescriptors())); publicFields.addAll(Arrays.asList(superclass.getFieldDescriptors())); int dotPos = className.lastIndexOf("."); String packageName = dotPos != -1 ? className.substring(0, dotPos) : null; - Set<String> interfaces = new HashSet<String>(); + ClassDescriptor[] superclassInterfaces = superclass.getInterfaces(); for (ClassDescriptor superclassInterface : superclassInterfaces) { interfaces.add(superclassInterface.getName()); Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/reflect/JavaFileParser.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/reflect/JavaFileParser.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/reflect/JavaFileParser.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -55,6 +55,7 @@ } public static ClassDescriptor parseJavaFile(String displayName, Reader src, ClassLoader classLoader) throws ClassNotFoundException { + //FIXME-TC20091205 : no now JAXX can look to interfaces, must add them // has some limitations -- it reports all members as public, leaves getDeclaredMethod and getDeclaredField // undefined, and doesn't report interfaces. It's safe to leave those the way they are for now, because // JAXX doesn't look at any of those for non-JAXX classes. @@ -90,6 +91,7 @@ ClassDescriptor superclassDescriptor = ClassDescriptorLoader.getClassDescriptor(parser.superclass, classLoader); publicMethods.addAll(Arrays.asList(superclassDescriptor.getMethodDescriptors())); publicFields.addAll(Arrays.asList(superclassDescriptor.getFieldDescriptors())); + //FIXME-TC20091205 : now JAXX can look to interfaces, must add them //Set<String> interfaces = new HashSet<String>(); //ClassDescriptor[] superclassInterfaces = superclassDescriptor.getInterfaces(); //for (ClassDescriptor superclassInterface : superclassInterfaces) { @@ -144,7 +146,9 @@ compiler.addImport(text); } else if (nodeType == JavaParserTreeConstants.JJTTYPEDECLARATION) { scanCompilationUnit(child); - } else if (nodeType == JavaParserTreeConstants.JJTCLASSORINTERFACEDECLARATION) { + //TC-20091204 : add enum support +// } else if (nodeType == JavaParserTreeConstants.JJTCLASSORINTERFACEDECLARATION) { + } else if (nodeType == JavaParserTreeConstants.JJTCLASSORINTERFACEDECLARATION || nodeType== JavaParserTreeConstants.JJTENUMDECLARATION) { scanClass(child); } } Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/tags/TagManager.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/tags/TagManager.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/tags/TagManager.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -20,7 +20,10 @@ */ package jaxx.compiler.tags; -import jaxx.compiler.*; +import jaxx.compiler.ClassMap; +import jaxx.compiler.CompilerException; +import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.JAXXEngine; import jaxx.compiler.reflect.ClassDescriptor; import jaxx.compiler.reflect.ClassDescriptorLoader; import org.apache.commons.logging.Log; @@ -226,8 +229,12 @@ public static DefaultObjectHandler getTagHandler(ClassDescriptor beanClass) throws CompilerException { try { if (beanClass == null) { - throw new NullPointerException(); + throw new NullPointerException("beanClass parameter can not be null"); } + if (beanClass.getName() == null) { + throw new NullPointerException("beanClass can not be null : "+beanClass); + } + String namespace = getNamespace(beanClass); String tag = getSimpleName(beanClass); DefaultObjectHandler handler = (DefaultObjectHandler) registeredTags.get(new QName(namespace, tag)); @@ -340,7 +347,7 @@ */ public static TagHandler getTagHandler(String namespace, String tag, boolean namespacePrefix, JAXXCompiler compiler) throws CompilerException { if (tag == null) { - throw new NullPointerException(); + throw new NullPointerException("tag parameter can not be null"); } if (namespace == null && defaultNamespaces.containsKey(tag)) { namespace = defaultNamespaces.get(tag); @@ -372,7 +379,8 @@ handler = registeredTags.get(new QName(namespace, tag)); if (handler == null) { try { - handler = getTagHandler(ClassDescriptorLoader.getClassDescriptor(className, compiler.getClassLoader())); + ClassDescriptor beanClass = ClassDescriptorLoader.getClassDescriptor(className, compiler.getClassLoader()); + handler = getTagHandler(beanClass); } catch (ClassNotFoundException e) { e.printStackTrace(); } Deleted: trunk/jaxx-compiler/src/test/java/jaxx/compiler/JavaFileParserTest.java =================================================================== --- trunk/jaxx-compiler/src/test/java/jaxx/compiler/JavaFileParserTest.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/test/java/jaxx/compiler/JavaFileParserTest.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -1,77 +0,0 @@ -/* - * *##% - * JAXX Compiler - * Copyright (C) 2008 - 2009 CodeLutin - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/lgpl-3.0.html>. - * ##%* - */ -package jaxx.compiler; - -import jaxx.compiler.CompilerException; -import jaxx.compiler.reflect.ClassDescriptor; -import jaxx.compiler.reflect.JavaFileParser; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import java.io.File; -import java.io.FileReader; -import java.io.Reader; - -public class JavaFileParserTest { - - - /** log */ - protected static final Log log = LogFactory.getLog(JavaFileParserTest.class); - - static File basedir; - - @BeforeClass - public static void initBaseDir() { - // get maven env basedir - String basedir = System.getenv("basedir"); - if (basedir == null) { - basedir = new File("").getAbsolutePath(); - } - JavaFileParserTest.basedir = new File(basedir); - } - - @Test - public void testParseJavaSourceFile() throws Exception { - - File testSourceRoot = new File(basedir, "src" + File.separator + "test" + File.separator + "java"); - Assert.assertTrue(testSourceRoot.exists()); - - File src = new File(testSourceRoot, getClass().getName().replaceAll("\\.", File.separator) + ".java"); - Assert.assertTrue(src.exists()); - log.info("trying parsing file " + src); - Reader reader = new FileReader(src); - try { - ClassDescriptor result = JavaFileParser.parseJavaFile("TestParserJava", reader, getClass().getClassLoader()); - Assert.assertNotNull(result); - - } catch (CompilerException e) { - log.error("could not parse file " + src + " for reason " + e.getMessage(), e); - Assert.fail(e.getMessage()); - } - finally { - reader.close(); - } - } - -} Deleted: trunk/jaxx-compiler/src/test/java/jaxx/compiler/JavaMethodTest.java =================================================================== --- trunk/jaxx-compiler/src/test/java/jaxx/compiler/JavaMethodTest.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-compiler/src/test/java/jaxx/compiler/JavaMethodTest.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -1,72 +0,0 @@ -/* - * *##% - * JAXX Compiler - * Copyright (C) 2008 - 2009 CodeLutin - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/lgpl-3.0.html>. - * ##%* - */ -package jaxx.compiler; - -import jaxx.compiler.java.JavaMethod; -import jaxx.compiler.java.JavaMethod.MethodOrder; -import org.junit.Assert; -import org.junit.Test; - -import java.lang.reflect.Modifier; -import java.util.EnumSet; - -/** @author chemit */ -public class JavaMethodTest { - - @Test - public void testGetMethodOrderScope() { - EnumSet<MethodOrder> allConstants = EnumSet.allOf(MethodOrder.class); - - EnumSet<MethodOrder> constants; - - constants = JavaMethod.getMethodOrderScope(allConstants, Modifier.STATIC); - - Assert.assertEquals(1, constants.size()); - Assert.assertTrue(constants.contains(MethodOrder.statics)); - - constants = JavaMethod.getMethodOrderScope(allConstants, Modifier.PUBLIC); - - Assert.assertEquals(8, constants.size()); - Assert.assertTrue(constants.contains(MethodOrder.constructors)); - Assert.assertTrue(constants.contains(MethodOrder.JAXXObject)); - Assert.assertTrue(constants.contains(MethodOrder.JAXXContext)); - Assert.assertTrue(constants.contains(MethodOrder.JAXXValidation)); - Assert.assertTrue(constants.contains(MethodOrder.events)); - Assert.assertTrue(constants.contains(MethodOrder.publicGetters)); - Assert.assertTrue(constants.contains(MethodOrder.publicSetters)); - Assert.assertTrue(constants.contains(MethodOrder.otherPublic)); - - constants = JavaMethod.getMethodOrderScope(allConstants, Modifier.PROTECTED); - - Assert.assertEquals(3, constants.size()); - Assert.assertTrue(constants.contains(MethodOrder.protectedGetters)); - Assert.assertTrue(constants.contains(MethodOrder.protecteds)); - Assert.assertTrue(constants.contains(MethodOrder.createMethod)); - - - constants = JavaMethod.getMethodOrderScope(allConstants, Modifier.PRIVATE); - Assert.assertEquals(3, constants.size()); - Assert.assertTrue(constants.contains(MethodOrder.createMethod)); - Assert.assertTrue(constants.contains(MethodOrder.packageLocal)); - Assert.assertTrue(constants.contains(MethodOrder.privates)); - - } -} Added: trunk/jaxx-compiler/src/test/java/jaxx/compiler/binding/JavaParserUtilTest.java =================================================================== --- trunk/jaxx-compiler/src/test/java/jaxx/compiler/binding/JavaParserUtilTest.java (rev 0) +++ trunk/jaxx-compiler/src/test/java/jaxx/compiler/binding/JavaParserUtilTest.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -0,0 +1,303 @@ +package jaxx.compiler.binding; + +import jaxx.compiler.java.parser.JavaParser; +import jaxx.compiler.java.parser.SimpleNode; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Test; + +import java.io.StringReader; +import java.util.*; + +/** + * Created: 5 déc. 2009 + * + * @author Tony Chemit <chemit@codelutin.com> Copyright Code Lutin + * @version $Revision$ + * <p/> + * Mise a jour: $Date$ par : + * $Author: tchemit $ + */ +public class JavaParserUtilTest { + + /** + * Logger + */ + private static final Log log = LogFactory.getLog(JavaParserUtilTest.class); + + Map<SimpleNode, List<SimpleNode>> store = new LinkedHashMap<SimpleNode, List<SimpleNode>>(); + Map<SimpleNode, List<SimpleNode>> casts = new LinkedHashMap<SimpleNode, List<SimpleNode>>(); + List<SimpleNode> literals = new ArrayList<SimpleNode>(); + Set<String> requirements; + Iterator<SimpleNode> simpleNodeIterator; + Iterator<String> requirementsIterator; + SimpleNode node; + String source; + + @Test + public void testGetExpressionsWithLiterals() throws Exception { + + parseSourceAndGetExpressions("1", 1, 1); + assertNextNode(source, 0); + assertLiteralNode(0); + + parseSourceAndGetExpressions("true", 1, 1); + assertNextNode(source, 0); + assertLiteralNode(0); + + parseSourceAndGetExpressions("\"1\"", 1, 1); + assertNextNode(source, 0); + assertLiteralNode(0); + + parseSourceAndGetExpressions("\"1\" + \"2\"", 2, 2); + assertNextNode("\"1\"", 0); + assertLiteralNode(0); + assertNextNode("\"2\"", 0); + assertLiteralNode(1); + + parseSourceAndGetExpressions("1.1 + 2", 2, 2); + assertNextNode("1.1", 0); + assertLiteralNode(0); + assertNextNode("2", 0); + assertLiteralNode(1); + } + + @Test + public void testGetExpressionsWithNoLiterals() throws Exception { + + parseSourceAndGetExpressions("a", 0, 1); + assertNextNode(source, 0); + + parseSourceAndGetExpressions("a.getText()", 0, 1); + assertNextNode(source, 0); + + parseSourceAndGetExpressions("a.getText().getLength()", 0, 1); + assertNextNode(source, 0); + + parseSourceAndGetExpressions("getText()", 0, 1); + assertNextNode(source, 0); + + parseSourceAndGetExpressions("getText(a)", 0, 2); + assertNextNode(source, 1); + assertNextNode("a", 0); + + parseSourceAndGetExpressions("getText(a, b, c)", 0, 4); + assertNextNode(source, 3); + assertNextNode("a", 0); + assertNextNode("b", 0); + assertNextNode("c", 0); + + parseSourceAndGetExpressions("getText(a + b, c)", 0, 4); + assertNextNode(source, 3); + assertNextNode("a", 0); + assertNextNode("b", 0); + assertNextNode("c", 0); + + parseSourceAndGetExpressions("getText(a + b + c)", 0, 4); + assertNextNode(source, 3); + assertNextNode("a", 0); + assertNextNode("b", 0); + assertNextNode("c", 0); + + parseSourceAndGetExpressions("(Hum)a", 0, 1); + assertNextNode("a", 0); + + parseSourceAndGetExpressions("(Hum) a", 0, 1); + assertNextNode("a", 0); + + parseSourceAndGetExpressions("((Hum) a)", 0, 2); + assertNextNode(source, 1); + assertNextNode("a", 0); + + parseSourceAndGetExpressions("((Hum) a).getText()", 0, 2); + assertNextNode(source, 1); + assertNextNode("a", 0); + } + + @Test + public void testGetExpressions() throws Exception { + + parseSourceAndGetExpressions("getText(\"a\")", 1, 2); + assertNextNode(source, 1); + assertNextNode("\"a\"", 0); + assertLiteralNode(0); + + parseSourceAndGetExpressions("SwingUtil.getText(\"a\")", 1, 2); + assertNextNode(source, 1); + assertNextNode("\"a\"", 0); + assertLiteralNode(0); + + parseSourceAndGetExpressions("getText2() && getText(\"a.b\")", 1, 3); + assertNextNode("getText2()", 0); + assertNextNode("getText(\"a.b\")", 1); + assertNextNode("\"a.b\"", 0); + assertLiteralNode(0); + + parseSourceAndGetExpressions("SwingUtil.getText2() && getText(\"a.b\")", 1, 3); + assertNextNode("SwingUtil.getText2()", 0); + assertNextNode("getText(\"a.b\")", 1); + assertNextNode("\"a.b\"", 0); + assertLiteralNode(0); + + parseSourceAndGetExpressions("SwingUtil.getText2() && SwingUtil2.getText(\"a.b\")", 1, 3); + assertNextNode("SwingUtil.getText2()", 0); + assertNextNode("SwingUtil2.getText(\"a.b\")", 1); + assertNextNode("\"a.b\"", 0); + assertLiteralNode(0); + + parseSourceAndGetExpressions("SwingUtil.get().getText2() && SwingUtil2.getText(\"a.b\")", 1, 3); + assertNextNode("SwingUtil.get().getText2()", 0); + assertNextNode("SwingUtil2.getText(\"a.b\")", 1); + assertNextNode("\"a.b\"", 0); + assertLiteralNode(0); + } + + @Test + public void testGetMethodInvocationParameters() throws Exception { + getMethodInvocationParameters("a", null); + getMethodInvocationParameters("a(", null); + getMethodInvocationParameters("a( ", null); + getMethodInvocationParameters("a)", null); + getMethodInvocationParameters("a )", null); + getMethodInvocationParameters("a()", ""); + getMethodInvocationParameters("a( )", ""); + getMethodInvocationParameters("a( yo )", "yo"); + getMethodInvocationParameters("SwingUtil.a( yo )", "yo"); + getMethodInvocationParameters("SwingUtil.a( yo, ya )", "yo, ya"); + + } + + @Test + public void testGetRequirementsWithLiterals() throws Exception { + + parseSourceAndGetRequirements("1"); + + parseSourceAndGetRequirements("true"); + + parseSourceAndGetRequirements("\"1\""); + + parseSourceAndGetRequirements("\"1\" + \"2\""); + + parseSourceAndGetRequirements("1.1 + 2"); + } + + + @Test + public void testGetRequirementsWithNoLiterals() throws Exception { + + parseSourceAndGetRequirements("a"); + + parseSourceAndGetRequirements("a.getText()", "a"); + + parseSourceAndGetRequirements("a.getText().getLength()", "a", "a.getText()"); + + parseSourceAndGetRequirements("getText()"); + + parseSourceAndGetRequirements("getText(a)"); + + parseSourceAndGetRequirements("getText(a, b, c)"); + + parseSourceAndGetRequirements("getText(a + b, c)"); + + parseSourceAndGetRequirements("getText(a + b + c)"); + + parseSourceAndGetRequirements("(Hum)a"); + + parseSourceAndGetRequirements("((Hum)a)"); + + parseSourceAndGetRequirements("((Hum)a).getText()", "a"); + + parseSourceAndGetRequirements("((Hum)a).getB().getText()", "a", "a.getB()"); + + parseSourceAndGetRequirements("((Hum)a.getB()).getText()", "a", "a.getB()"); + } + + @Test + public void testGetRequirements() throws Exception { + + parseSourceAndGetRequirements("getText(\"a\")"); + + parseSourceAndGetRequirements("SwingUtil.getText(\"a\")", "SwingUtil"); + + parseSourceAndGetRequirements("getText2() && getText(\"a.b\")"); + + parseSourceAndGetRequirements("SwingUtil.getText2() && getText(\"a.b\")", "SwingUtil"); + + parseSourceAndGetRequirements("SwingUtil.getText2() && SwingUtil2.getText(\"a.b\")", "SwingUtil", "SwingUtil2"); + + parseSourceAndGetRequirements("SwingUtil.get().getText2() && SwingUtil2.getText(\"a.b\")", "SwingUtil2", "SwingUtil", "SwingUtil.get()"); + + } + + protected void parseSourceAndGetExpressions(String source, int expectedNbLiterals, int expectedNbExpressions) { + + // clean stores + literals.clear(); + + parseSource(source); + + Assert.assertEquals(expectedNbLiterals, literals.size()); + Assert.assertEquals(expectedNbExpressions, store.size()); + + simpleNodeIterator = store.keySet().iterator(); + } + + protected void parseSourceAndGetRequirements(String source, String... expected) { + + parseSource(source); + + requirements = JavaParserUtil.getRequired(store.keySet(), casts); + Assert.assertEquals(expected.length, requirements == null ? 0 : requirements.size()); + if (expected.length > 0) { + + requirementsIterator = requirements.iterator(); + for (String s : expected) { + Assert.assertTrue(requirementsIterator.hasNext()); + Assert.assertEquals(s, requirementsIterator.next()); + } + } + } + + protected void getMethodInvocationParameters(String code, String expected) { + String invocationParameters = JavaParserUtil.getMethodInvocationParameters(code); + Assert.assertEquals(expected, invocationParameters); + } + + protected void assertNextNode(String expectedText, int nbDep) { + + Assert.assertTrue(simpleNodeIterator.hasNext()); + node = simpleNodeIterator.next(); + Assert.assertNotNull(node); + Assert.assertEquals(expectedText, node.getText().trim()); + Assert.assertEquals(nbDep, store.get(node).size()); + } + + private void parseSource(String source) { + + this.source = source; + // clean stores + store.clear(); + literals.clear(); + casts.clear(); + + if (log.isInfoEnabled()) { + log.info(source); + } + + JavaParser p; + SimpleNode node; + p = new JavaParser(new StringReader(source)); + while (!p.Line()) { + node = p.popNode(); + JavaParserUtil.getExpressions(node, store, literals, casts); + } + } + + protected void assertLiteralNode(int nbDep) { + Assert.assertNotNull(node); + Assert.assertTrue(nbDep <= literals.size()); + Assert.assertEquals(node, literals.get(nbDep)); + } + +} Property changes on: trunk/jaxx-compiler/src/test/java/jaxx/compiler/binding/JavaParserUtilTest.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: trunk/jaxx-compiler/src/test/java/jaxx/compiler/java/JavaFieldTest.java =================================================================== --- trunk/jaxx-compiler/src/test/java/jaxx/compiler/java/JavaFieldTest.java (rev 0) +++ trunk/jaxx-compiler/src/test/java/jaxx/compiler/java/JavaFieldTest.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -0,0 +1,70 @@ +package jaxx.compiler.java; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Test; + +import java.lang.reflect.Modifier; +import java.util.EnumSet; + +/** + * Created: 3 déc. 2009 + * + * @author Tony Chemit <chemit@codelutin.com> Copyright Code Lutin + * @version $Revision$ + * <p/> + * Mise a jour: $Date$ par : + * $Author: tchemit $ + */ +public class JavaFieldTest { + /** + * Logger + */ + private static final Log log = LogFactory.getLog(JavaFieldTest.class); + + @Test + public void testGetFieldOrderScope() { + + EnumSet<JavaField.FieldOrder> allConstants = EnumSet.allOf(JavaField.FieldOrder.class); + if (log.isDebugEnabled()) { + for (JavaField.FieldOrder allConstant : allConstants) { + log.debug("\n" + allConstant.getHeader()); + } + } + + EnumSet<JavaField.FieldOrder> constants; + + constants = JavaField.getFieldOrderScope(allConstants, Modifier.STATIC); + + Assert.assertEquals(4, constants.size()); + Assert.assertTrue(constants.contains(JavaField.FieldOrder.staticsBean)); + Assert.assertTrue(constants.contains(JavaField.FieldOrder.staticsOthers)); + Assert.assertTrue(constants.contains(JavaField.FieldOrder.staticsPublicBindings)); + Assert.assertTrue(constants.contains(JavaField.FieldOrder.staticsPrivateBindings)); + + constants = JavaField.getFieldOrderScope(allConstants, Modifier.PUBLIC); + + Assert.assertEquals(3, constants.size()); + Assert.assertTrue(constants.contains(JavaField.FieldOrder.staticsBean)); +// Assert.assertTrue(constants.contains(JavaField.FieldOrder.staticsOthers)); + Assert.assertTrue(constants.contains(JavaField.FieldOrder.staticsPublicBindings)); + Assert.assertTrue(constants.contains(JavaField.FieldOrder.publicFields)); + + constants = JavaField.getFieldOrderScope(allConstants, Modifier.PROTECTED); + + Assert.assertEquals(2, constants.size()); +// Assert.assertTrue(constants.contains(JavaField.FieldOrder.staticsOthers)); + Assert.assertTrue(constants.contains(JavaField.FieldOrder.protectedFields)); + Assert.assertTrue(constants.contains(JavaField.FieldOrder.internalFields)); + + + constants = JavaField.getFieldOrderScope(allConstants, Modifier.PRIVATE); + Assert.assertEquals(3, constants.size()); + Assert.assertTrue(constants.contains(JavaField.FieldOrder.staticsPrivateBindings)); +// Assert.assertTrue(constants.contains(JavaField.FieldOrder.staticsOthers)); + Assert.assertTrue(constants.contains(JavaField.FieldOrder.privateFields)); + Assert.assertTrue(constants.contains(JavaField.FieldOrder.internalFields)); + + } +} Property changes on: trunk/jaxx-compiler/src/test/java/jaxx/compiler/java/JavaFieldTest.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Copied: trunk/jaxx-compiler/src/test/java/jaxx/compiler/java/JavaMethodTest.java (from rev 1674, trunk/jaxx-compiler/src/test/java/jaxx/compiler/JavaMethodTest.java) =================================================================== --- trunk/jaxx-compiler/src/test/java/jaxx/compiler/java/JavaMethodTest.java (rev 0) +++ trunk/jaxx-compiler/src/test/java/jaxx/compiler/java/JavaMethodTest.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -0,0 +1,86 @@ +/* + * *##% + * JAXX Compiler + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * ##%* + */ +package jaxx.compiler.java; + +import jaxx.compiler.java.JavaMethod.MethodOrder; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Test; + +import java.lang.reflect.Modifier; +import java.util.EnumSet; + +/** + * @author chemit + */ +public class JavaMethodTest { + /** + * Logger + */ + private static final Log log = LogFactory.getLog(JavaMethodTest.class); + + @Test + public void testGetMethodOrderScope() { + + EnumSet<MethodOrder> allConstants = EnumSet.allOf(MethodOrder.class); + if (log.isDebugEnabled()) { + for (MethodOrder allConstant : allConstants) { + log.debug("\n" + allConstant.getHeader()); + } + } + + EnumSet<MethodOrder> constants; + + constants = JavaMethod.getMethodOrderScope(allConstants, Modifier.STATIC); + + Assert.assertEquals(1, constants.size()); + Assert.assertTrue(constants.contains(MethodOrder.statics)); + + constants = JavaMethod.getMethodOrderScope(allConstants, Modifier.PUBLIC); + + Assert.assertEquals(8, constants.size()); + Assert.assertTrue(constants.contains(MethodOrder.constructors)); + Assert.assertTrue(constants.contains(MethodOrder.JAXXObject)); + Assert.assertTrue(constants.contains(MethodOrder.JAXXContext)); + Assert.assertTrue(constants.contains(MethodOrder.JAXXValidation)); + Assert.assertTrue(constants.contains(MethodOrder.events)); + Assert.assertTrue(constants.contains(MethodOrder.publicGetters)); + Assert.assertTrue(constants.contains(MethodOrder.publicSetters)); + Assert.assertTrue(constants.contains(MethodOrder.otherPublic)); + + constants = JavaMethod.getMethodOrderScope(allConstants, Modifier.PROTECTED); + + Assert.assertEquals(3, constants.size()); + Assert.assertTrue(constants.contains(MethodOrder.protectedGetters)); + Assert.assertTrue(constants.contains(MethodOrder.protecteds)); + Assert.assertTrue(constants.contains(MethodOrder.createMethod)); + + + constants = JavaMethod.getMethodOrderScope(allConstants, Modifier.PRIVATE); + Assert.assertEquals(4, constants.size()); + Assert.assertTrue(constants.contains(MethodOrder.internalMethod)); + Assert.assertTrue(constants.contains(MethodOrder.createMethod)); + Assert.assertTrue(constants.contains(MethodOrder.packageLocal)); + Assert.assertTrue(constants.contains(MethodOrder.privates)); + + } +} Property changes on: trunk/jaxx-compiler/src/test/java/jaxx/compiler/java/JavaMethodTest.java ___________________________________________________________________ Added: svn:mergeinfo + Copied: trunk/jaxx-compiler/src/test/java/jaxx/compiler/reflect/JavaFileParserTest.java (from rev 1674, trunk/jaxx-compiler/src/test/java/jaxx/compiler/JavaFileParserTest.java) =================================================================== --- trunk/jaxx-compiler/src/test/java/jaxx/compiler/reflect/JavaFileParserTest.java (rev 0) +++ trunk/jaxx-compiler/src/test/java/jaxx/compiler/reflect/JavaFileParserTest.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -0,0 +1,104 @@ +/* + * *##% + * JAXX Compiler + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * ##%* + */ +package jaxx.compiler.reflect; + +import jaxx.compiler.CompilerException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.*; + +public class JavaFileParserTest { + + + /** + * log + */ + protected static final Log log = LogFactory.getLog(JavaFileParserTest.class); + + static File basedir; + static File testSourceRoot; + + @BeforeClass + public static void initBaseDir() { + // get maven env basedir + String basedir = System.getenv("basedir"); + if (basedir == null) { + basedir = new File("").getAbsolutePath(); + } + JavaFileParserTest.basedir = new File(basedir); + testSourceRoot = new File(basedir, "src" + File.separator + "test" + File.separator + "java"); + } + + @Test + public void testParseJavaSourceFile() throws Exception { + + Assert.assertTrue(testSourceRoot.exists()); + + File src = new File(testSourceRoot, getClass().getName().replaceAll("\\.", File.separator) + ".java"); + Assert.assertTrue(src.exists()); + log.info("trying parsing file " + src); + Reader reader = new FileReader(src); + try { + ClassDescriptor result = JavaFileParser.parseJavaFile("TestParserJava", reader, getClass().getClassLoader()); + Assert.assertNotNull(result); + + } catch (CompilerException e) { + log.error("could not parse file " + src + " for reason " + e.getMessage(), e); + Assert.fail(e.getMessage()); + } + finally { + reader.close(); + } + } + + @Test + public void testParseEnum() throws ClassNotFoundException, IOException { + + File src = new File(testSourceRoot, MyEnum.class.getName().replaceAll("\\.", File.separator) + ".java"); + if (log.isInfoEnabled()) { + log.info("file to parse " + src); + } + Assert.assertTrue(src.exists()); + + InputStream in = new FileInputStream(src); + Assert.assertNotNull(in); + try { + Reader reader = new InputStreamReader(in); + + ClassDescriptor descriptor = JavaFileParser.parseJavaFile("MyEnum", reader, null); + + Assert.assertNotNull(descriptor); + if (log.isInfoEnabled()) { + log.info("description found : " + descriptor); + } + Assert.assertNotNull(descriptor.getName()); + } finally { + + in.close(); + + } + } + +} Property changes on: trunk/jaxx-compiler/src/test/java/jaxx/compiler/reflect/JavaFileParserTest.java ___________________________________________________________________ Added: svn:mergeinfo + Added: trunk/jaxx-compiler/src/test/java/jaxx/compiler/reflect/MyEnum.java =================================================================== --- trunk/jaxx-compiler/src/test/java/jaxx/compiler/reflect/MyEnum.java (rev 0) +++ trunk/jaxx-compiler/src/test/java/jaxx/compiler/reflect/MyEnum.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -0,0 +1,15 @@ +package jaxx.compiler.reflect; + +/** + * Created: 4 déc. 2009 + * + * @author Tony Chemit <chemit@codelutin.com> Copyright Code Lutin + * @version $Revision$ + * <p/> + * Mise a jour: $Date$ par : + * $Author: tchemit $ + */ +public enum MyEnum { + + A, B +} Property changes on: trunk/jaxx-compiler/src/test/java/jaxx/compiler/reflect/MyEnum.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Deleted: trunk/jaxx-runtime/src/main/java/jaxx/runtime/JAXXBinding.java =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/JAXXBinding.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/JAXXBinding.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -1,95 +0,0 @@ -/* - * *##% - * JAXX Runtime - * Copyright (C) 2008 - 2009 CodeLutin - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/lgpl-3.0.html>. - * ##%* - */ -package jaxx.runtime; - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; - - -/** - * A <code>PropertyChangeListener</code> which processes a data binding when it receives a - * <code>PropertyChangeEvent</code>. - */ -public abstract class JAXXBinding implements PropertyChangeListener { - /** - * Id of the binding - */ - private String id; - - /** - * Creates a new Data binding which will run the given data binding - * when it receives a <code>PropertyChangeEvent</code>. - * - * @param id the name of the data binding to run - */ - public JAXXBinding(String id) { - this.id = id; - } - - public String getId() { - return id; - } - - @Override - public String toString() { - return super.toString() + ":" + id; - } - - /** - * Processes the data binding in response to a <code>PropertyChangeEvent</code>. - * - * @param e the event which triggered the binding - */ - @Override - public void propertyChange(PropertyChangeEvent e) { -// object.processDataBinding(id); - - processDataBinding(); - - //TC-20091201 : I really don't see the point - // I comment the code, and still working fine ? Any trick - //TODO-20091201 Must test on a lot of cases before next release 2.0.0-beta-2 - // for now, handle dependency changes by always removing & reapplying - // the binding. We should be more efficient and only do this when it's - // actually necessary -// object.removeDataBinding(id); -// object.applyDataBinding(id); - } - - /** - * Apply the binding without processing it (say just install listeners). - */ - public abstract void applyDataBinding(); - - /** - * Processes the binding. - */ - public abstract void processDataBinding(); - - /** - * Remove the binding. - */ - public abstract void removeDataBinding(); -// -// public void propertyChange() { -// propertyChange(null); -// } -} \ No newline at end of file Added: trunk/jaxx-runtime/src/main/java/jaxx/runtime/JAXXBinding.java =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/JAXXBinding.java (rev 0) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/JAXXBinding.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -0,0 +1,46 @@ +package jaxx.runtime; + +import java.beans.PropertyChangeListener; + +/** + * Created: 5 déc. 2009 + * + * @author Tony Chemit <chemit@codelutin.com> Copyright Code Lutin + * @version $Revision$ + * <p/> + * Mise a jour: $Date$ par : + * $Author: tchemit $ + */ +public interface JAXXBinding extends PropertyChangeListener { + /** + * @return the unique id of a binding + */ + String getId(); + + /** + * @return the {@link jaxx.runtime.JAXXObject} which owns the binding + */ + JAXXObject getSource(); + + /** + * This state is not used actually, but will be usefull later... + * + * @return {@code true} if binding was registred as a default binding, {@code false} otherwise + */ + boolean isDefaultBinding(); + + /** + * Apply the binding without processing it (say just install listeners). + */ + void applyDataBinding(); + + /** + * Processes the binding. + */ + void processDataBinding(); + + /** + * Remove the binding. + */ + void removeDataBinding(); +} Property changes on: trunk/jaxx-runtime/src/main/java/jaxx/runtime/JAXXBinding.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Modified: trunk/jaxx-runtime/src/main/java/jaxx/runtime/JAXXObject.java =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/JAXXObject.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/JAXXObject.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -51,6 +51,18 @@ JAXXContext getDelegateContext(); /** + * @return all the databinding registred on the jaxx object + */ + JAXXBinding[] getDataBindings(); + + /** + * Register a new binding in the jaxx object. + * + * @param binding the binding to add + */ + void registerDataBinding(JAXXBinding binding); + + /** * Apply the data bind by name and then process it. * * @param id the id of the databinding @@ -68,6 +80,17 @@ void processDataBinding(String dest); /** + * Processes a data binding by name. Data binding names are comprised of an object ID and a property name: + * for example, the data binding in the tag <code><JLabel id='label' text='{foo.getText()}'/></code> is + * named <code>"label.text"</code>. Processing a data binding causes it to reevaluate its expression, in this + * case <code>foo.getText()</code>. + * + * @param dest the name of the data binding to run + * @param force flag to force binding, even if already on run + */ + void processDataBinding(String dest, boolean force); + + /** * Remove a databinding by name. * * @param id the name of databinding to remove Modified: trunk/jaxx-runtime/src/main/java/jaxx/runtime/Util.java =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/Util.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/Util.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -114,7 +114,7 @@ return contextEntryDef; } -// public static JAXXBinding registerBinding(Map<String, JAXXBinding> bindings, JAXXBinding binding) { +// public static DefaultJAXXBinding registerBinding(Map<String, DefaultJAXXBinding> bindings, DefaultJAXXBinding binding) { // bindings.put(binding.getId(), binding); //// binding.applyDataBinding(); //// binding.processDataBinding(); @@ -381,6 +381,17 @@ src.applyDataBinding(binding); } } + /** + * Convinient method to apply more than one binding on a JAXX ui. + * + * @param src the ui to treate + * @param bindings the list of binding to process. + */ + public static void applyDataBinding(JAXXObject src, Collection<String> bindings) { + for (String binding : bindings) { + src.applyDataBinding(binding); + } + } /** * Convinient method to process more than one binding on a JAXX ui. Copied: trunk/jaxx-runtime/src/main/java/jaxx/runtime/binding/DefaultJAXXBinding.java (from rev 1674, trunk/jaxx-runtime/src/main/java/jaxx/runtime/JAXXBinding.java) =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/binding/DefaultJAXXBinding.java (rev 0) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/binding/DefaultJAXXBinding.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -0,0 +1,131 @@ +/* + * *##% + * JAXX Runtime + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * ##%* + */ +package jaxx.runtime.binding; + +import jaxx.runtime.JAXXBinding; +import jaxx.runtime.JAXXObject; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.beans.PropertyChangeEvent; + + +/** + * A <code>PropertyChangeListener</code> which processes a data binding when it receives a + * <code>PropertyChangeEvent</code>. + */ +public abstract class DefaultJAXXBinding implements JAXXBinding { + + /** + * Logger + */ + private static final Log log = LogFactory.getLog(DefaultJAXXBinding.class); + /** + * Counter of all bindings hits + */ + private static long NB = 0; + /** + * Counter of current binding hits + */ + private long nb = 0; + + /** + * Id of the binding + */ + private final String id; + /** + * The source of the binding. + */ + protected final JAXXObject source; + /** + * flag to know {@code true} : if the binding was init from a generated jaxx object, {@code false} otherwise. + */ + protected final boolean defaultBinding; + + /** + * Creates a new Data binding which will run the given data binding + * when it receives a <code>PropertyChangeEvent</code>. + * + * @param source the {@link jaxx.runtime.JAXXObject} source of the binding + * @param id the name of the data binding to run + * @param defaultBinding flag to knwon if binding is coming from a generated jaxx object ({@code true}). + */ + public DefaultJAXXBinding(JAXXObject source, String id, boolean defaultBinding) { + this.source = source; + this.id = id; + this.defaultBinding = defaultBinding; + } + + @Override + public String getId() { + return id; + } + + @Override + public JAXXObject getSource() { + return source; + } + + @Override + public boolean isDefaultBinding() { + return defaultBinding; + } + + @Override + public String toString() { + return super.toString() + ":" + id; + } + + private static final String LOG_START_PATTERN = ">> (hits:%1$5d, total:%2$5d) on %3$s"; + private static final String LOG_END_PATTERN = "<< %4$3d (hits:%1$5d, total:%2$5d) on %3$s"; + + /** + * Processes the data binding in response to a <code>PropertyChangeEvent</code>. + * <p/> + * When the binding is wake up, delegate the process to the source object which + * can manage re-entrant code (can not process a re-entrant event). + * + * @param e the event which triggered the binding + */ + @Override + public void propertyChange(PropertyChangeEvent e) { + long count = NB; + if (log.isDebugEnabled()) { + log.debug(String.format(LOG_START_PATTERN, (++nb), (++NB), this)); + } + //TODO-TC-20091202 perharps could we have a nicer way to process it, + // let the source deal with it to avoid re-entrant code + source.processDataBinding(id); + + //TODO-20091201 Must test on a lot of cases before next release 2.0.0-beta-2 + //TC-20091201 : I really don't see the point + // I comment the code, and still working fine ? Any trick + // for now, handle dependency changes by always removing & reapplying + // the binding. We should be more efficient and only do this when it's + // actually necessary +// source.removeDataBinding(id); +// source.applyDataBinding(id); + if (log.isDebugEnabled()) { + log.debug(String.format(LOG_END_PATTERN, (++nb), (++NB), this, (NB - count))); + } + } + +} \ No newline at end of file Property changes on: trunk/jaxx-runtime/src/main/java/jaxx/runtime/binding/DefaultJAXXBinding.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: trunk/jaxx-runtime/src/main/java/jaxx/runtime/binding/SimpleJAXXObjectBinding.java =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/binding/SimpleJAXXObjectBinding.java (rev 0) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/binding/SimpleJAXXObjectBinding.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -0,0 +1,60 @@ +package jaxx.runtime.binding; + +import jaxx.runtime.JAXXObject; + +/** + * Created: 5 déc. 2009 + * + * @author Tony Chemit <chemit@codelutin.com> Copyright Code Lutin + * @version $Revision$ + * <p/> + * Mise a jour: $Date$ par : + * $Author: tchemit $ + */ +public abstract class SimpleJAXXObjectBinding extends DefaultJAXXBinding { + + protected final String[] propertyNames; + + /** + * Creates a new Data binding which will run the given data binding + * when it receives a <code>PropertyChangeEvent</code>. + * + * @param source the {@link jaxx.runtime.JAXXObject} source of the binding + * @param id the name of the data binding to run + * @param defaultBinding flag to knwon if binding is coming from a generated jaxx object ({@code true}). + * @param propertyNames the name of properties to listen on source + */ + public SimpleJAXXObjectBinding(JAXXObject source, String id, boolean defaultBinding, String... propertyNames) { + super(source, id, defaultBinding); + if (propertyNames == null || propertyNames.length == 0) { + throw new IllegalArgumentException("must at least have one propertyName "); + } + this.propertyNames = propertyNames; + } + + public boolean canApply() { + return true; + } + + public String[] getPropertyNames() { + return propertyNames; + } + + @Override + public void applyDataBinding() { + if (canApply()) { + for (String s : propertyNames) { + source.addPropertyChangeListener(s, this); + } + } + } + + @Override + public void removeDataBinding() { + if (canApply()) { + for (String s : propertyNames) { + source.removePropertyChangeListener(s, this); + } + } + } +} Property changes on: trunk/jaxx-runtime/src/main/java/jaxx/runtime/binding/SimpleJAXXObjectBinding.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Modified: trunk/jaxx-runtime/src/test/java/jaxx/runtime/context/DefaultJAXXContextTest.java =================================================================== --- trunk/jaxx-runtime/src/test/java/jaxx/runtime/context/DefaultJAXXContextTest.java 2009-12-08 17:19:34 UTC (rev 1678) +++ trunk/jaxx-runtime/src/test/java/jaxx/runtime/context/DefaultJAXXContextTest.java 2009-12-08 17:21:03 UTC (rev 1679) @@ -21,15 +21,10 @@ package jaxx.runtime.context; import jaxx.runtime.JAXXContext; -import jaxx.runtime.*; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import java.awt.Container; -import java.beans.PropertyChangeListener; -import java.util.Map; - /** * @author chemit */ @@ -44,41 +39,6 @@ ctxt = new DefaultJAXXContext(); } -// @Test(expected = IllegalStateException.class) -// public void testParentContainerFail_IllegalStateException() throws Exception { -// ctxt.getParentContainer(Container.class); -// } -// -// @Test(expected = IllegalStateException.class) -// public void testParentContainerFail_IllegalStateException2() throws Exception { -// ctxt.getParentContainer("null", Container.class); -// } - - -// @Test(expected = IllegalArgumentException.class) -// public void testParentContainerFail_IllegalArgumentException() throws Exception { -// -// // attach a fake ui (which is NOT a Container) -// ctxt.setUi(new MyJAXXObject()); -// ctxt.getParentContainer(Container.class); -// } -// -// @Test(expected = IllegalArgumentException.class) -// public void testParentContainerFail_IllegalArgumentException2() throws Exception { -// -// // attach a fake ui (which is NOT a Container) -// ctxt.setUi(new MyJAXXObject()); -// ctxt.getParentContainer(null, Container.class); -// } -// -// @Test(expected = IllegalArgumentException.class) -// public void testParentContainerFail_IllegalArgumentException3() throws Exception { -// -// // attach a fake ui (which is NOT a Container) -// ctxt.setUi(new MyJAXXObject()); -// ctxt.getParentContainer("null", Container.class); -// } - @Test public void testGetParentContext() throws Exception { JAXXContext expected, result; @@ -294,65 +254,4 @@ } - private static class MyJAXXObject extends DefaultJAXXContext implements JAXXObject { - private static final long serialVersionUID = 1L; - - @Override - public Object getObjectById(String id) { - return null; - } - - @Override - public Map<String, Object> get$objectMap() { - return null; - } - - @Override - public void applyDataBinding(String id) { - } - - @Override - public void removeDataBinding(String id) { - } - - @Override - public JAXXContext getDelegateContext() { - return null; - } - - @Override - public void processDataBinding(String dest) { - } - - @Override - public void firePropertyChange(String name, Object oldValue, Object newValue) { - } - - @Override - public void addPropertyChangeListener(PropertyChangeListener listener) { - } - - @Override - public void addPropertyChangeListener(String property, PropertyChangeListener listener) { - } - - @Override - public void removePropertyChangeListener(PropertyChangeListener listener) { - } - - @Override - public void removePropertyChangeListener(String property, PropertyChangeListener listener) { - } - - @Override - public <O extends Container> O getParentContainer(Class<O> clazz) { - return null; - } - - @Override - public <O extends Container> O getParentContainer(Object top, Class<O> clazz) { - return null; - } - - } }