]> source.dussan.org Git - vaadin-framework.git/commitdiff
Reduce generated ConnectorBundleLoaderImpl size. (#9379)
authordenisanisimov <denis@vaadin.com>
Tue, 4 Feb 2014 11:11:39 +0000 (13:11 +0200)
committerLeif Åstrand <leif@vaadin.com>
Wed, 12 Feb 2014 07:32:02 +0000 (07:32 +0000)
Change-Id: I49411e6893f3adc1c41cc690aca35cd919769625

client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java
client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java
client-compiler/src/com/vaadin/server/widgetsetutils/metadata/FieldProperty.java
client-compiler/src/com/vaadin/server/widgetsetutils/metadata/MethodProperty.java
client-compiler/src/com/vaadin/server/widgetsetutils/metadata/Property.java
client/src/com/vaadin/client/metadata/ConnectorBundleLoader.java
client/src/com/vaadin/client/metadata/Property.java
client/src/com/vaadin/client/metadata/TypeDataStore.java

index f8aa58606407a322507677fa1b69283131874773..1c06cea3fadb35c2f8ca730072cec8a9795a4bcb 100644 (file)
@@ -19,6 +19,8 @@ import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -74,6 +76,7 @@ public class ConnectorBundleLoaderFactory extends Generator {
         private final SourceWriter target;
         private final String baseName;
         private final int splitSize;
+        private final List<String> methodNames;
 
         // Seems to be undercounted by about 15%
         private int approximateChars = 0;
@@ -84,6 +87,8 @@ public class ConnectorBundleLoaderFactory extends Generator {
             this.target = target;
             this.baseName = baseName;
             this.splitSize = splitSize;
+            methodNames = new ArrayList<String>();
+            methodNames.add(baseName);
         }
 
         @Override
@@ -169,17 +174,34 @@ public class ConnectorBundleLoaderFactory extends Generator {
         }
 
         public void splitIfNeeded() {
+            splitIfNeeded(false, null);
+        }
+
+        public void splitIfNeeded(boolean isNative, String params) {
             if (approximateChars > splitSize) {
                 String newMethod = baseName + wrapCount++;
-                println("%s();", newMethod);
-                outdent();
-                println("}");
-                println("private void %s() {", newMethod);
+                String args = params == null ? "" : params;
+                if (isNative) {
+                    outdent();
+                    println("}-*/;");
+                    println("private native void %s(%s) /*-{", newMethod, args);
+                } else {
+                    println("%s();", newMethod);
+                    outdent();
+                    println("}");
+                    println("private void %s(%s) {", newMethod, args);
+                }
+                methodNames.add(newMethod);
                 indent();
 
                 approximateChars = 0;
             }
         }
+
+        public List<String> getMethodNames() {
+            return Collections.unmodifiableList(methodNames);
+        }
+
     }
 
     @Override
@@ -227,6 +249,8 @@ public class ConnectorBundleLoaderFactory extends Generator {
         w.indent();
 
         for (ConnectorBundle bundle : bundles) {
+            detectBadProperties(bundle, logger);
+
             String name = bundle.getName();
             boolean isEager = name
                     .equals(ConnectorBundleLoader.EAGER_BUNDLE_NAME);
@@ -275,12 +299,34 @@ public class ConnectorBundleLoaderFactory extends Generator {
             w.println("private void load() {");
             w.indent();
 
-            printBundleData(logger, w, bundle);
+            String loadNativeJsBundle = "loadJsBundle";
+            printBundleData(logger, w, bundle, loadNativeJsBundle);
 
             // Close load method
             w.outdent();
             w.println("}");
 
+            // Separate method for loading native JS stuff (e.g. callbacks)
+            String loadNativeJsMethodName = "loadNativeJs";
+            w.println("private native void %s(%s store) /*-{",
+                    loadNativeJsMethodName, TypeDataStore.class.getName());
+            w.indent();
+            List<String> jsMethodNames = printJsBundleData(logger, w, bundle,
+                    loadNativeJsMethodName);
+
+            w.outdent();
+            w.println("}-*/;");
+
+            // Call all generated native method inside one Java method to avoid
+            // refercences inside native methods to each other
+            w.println("private void %s(%s store) {", loadNativeJsBundle,
+                    TypeDataStore.class.getName());
+            w.indent();
+            printLoadJsBundleData(w, loadNativeJsBundle, jsMethodNames);
+            w.outdent();
+            w.println("}");
+
+            // onFailure method declaration starts
             w.println("public void onFailure(Throwable reason) {");
             w.indent();
 
@@ -315,27 +361,153 @@ public class ConnectorBundleLoaderFactory extends Generator {
         w.commit(logger);
     }
 
+    private void printLoadJsBundleData(SourceWriter w, String methodName,
+            List<String> methods) {
+        SplittingSourceWriter writer = new SplittingSourceWriter(w, methodName,
+                30000);
+
+        for (String method : methods) {
+            writer.println("%s(store);", method);
+            writer.splitIfNeeded();
+        }
+    }
+
+    private void detectBadProperties(ConnectorBundle bundle, TreeLogger logger)
+            throws UnableToCompleteException {
+        Map<JClassType, Set<String>> definedProperties = new HashMap<JClassType, Set<String>>();
+
+        for (Property property : bundle.getNeedsProperty()) {
+            JClassType beanType = property.getBeanType();
+            Set<String> usedPropertyNames = definedProperties.get(beanType);
+            if (usedPropertyNames == null) {
+                usedPropertyNames = new HashSet<String>();
+                definedProperties.put(beanType, usedPropertyNames);
+            }
+
+            String name = property.getName();
+            if (!usedPropertyNames.add(name)) {
+                logger.log(Type.ERROR, beanType.getQualifiedSourceName()
+                        + " has multiple properties with the name " + name
+                        + ". This can happen if there are multiple "
+                        + "setters with identical names ignoring case.");
+                throw new UnableToCompleteException();
+            }
+            if (!property.hasAccessorMethods()) {
+                logger.log(Type.ERROR, beanType.getQualifiedSourceName()
+                        + " has the property '" + name
+                        + "' without getter defined.");
+                throw new UnableToCompleteException();
+            }
+        }
+    }
+
+    private List<String> printJsBundleData(TreeLogger logger, SourceWriter w,
+            ConnectorBundle bundle, String methodName) {
+        SplittingSourceWriter writer = new SplittingSourceWriter(w, methodName,
+                30000);
+        Set<Property> needsProperty = bundle.getNeedsProperty();
+        for (Property property : needsProperty) {
+            writer.println("var data = {");
+            writer.indent();
+
+            writer.println("setter: function(bean, value) {");
+            writer.indent();
+            property.writeSetterBody(logger, writer, "bean", "value");
+            writer.outdent();
+            writer.println("},");
+
+            writer.println("getter: function(bean) {");
+            writer.indent();
+            property.writeGetterBody(logger, writer, "bean");
+            writer.outdent();
+            writer.println("}");
+
+            writer.outdent();
+            writer.println("};");
+
+            // Method declaration
+            writer.print(
+                    "store.@%s::setPropertyData(Ljava/lang/Class;Ljava/lang/String;Lcom/google/gwt/core/client/JavaScriptObject;)",
+                    TypeDataStore.class.getName());
+            writer.println("(@%s::class, '%s', data);", property.getBeanType()
+                    .getQualifiedSourceName(), property.getName());
+            writer.println();
+            writer.splitIfNeeded(true,
+                    String.format("%s store", TypeDataStore.class.getName()));
+        }
+        return writer.getMethodNames();
+    }
+
     private void printBundleData(TreeLogger logger, SourceWriter sourceWriter,
-            ConnectorBundle bundle) throws UnableToCompleteException {
+            ConnectorBundle bundle, String loadNativeJsMethodName)
+            throws UnableToCompleteException {
         // Split into new load method when reaching approximately 30000 bytes
         SplittingSourceWriter w = new SplittingSourceWriter(sourceWriter,
                 "load", 30000);
 
+        writeSuperClasses(w, bundle);
         writeIdentifiers(w, bundle);
         writeGwtConstructors(w, bundle);
         writeReturnTypes(w, bundle);
         writeInvokers(w, bundle);
         writeParamTypes(w, bundle);
         writeProxys(w, bundle);
-        wirteDelayedInfo(w, bundle);
-        writeProperites(logger, w, bundle);
-        writePropertyTypes(w, bundle);
-        writeSetters(logger, w, bundle);
-        writeGetters(logger, w, bundle);
+        writeDelayedInfo(w, bundle);
+
+        w.println("%s(store);", loadNativeJsMethodName);
+
+        // Must use Java code to generate Type data (because of Type[]), doing
+        // this after the JS property data has been initialized
+        writePropertyTypes(logger, w, bundle);
         writeSerializers(logger, w, bundle);
         writeDelegateToWidget(logger, w, bundle);
     }
 
+    private void writeSuperClasses(SplittingSourceWriter w,
+            ConnectorBundle bundle) {
+        List<JClassType> needsSuperclass = new ArrayList<JClassType>(
+                bundle.getNeedsSuperclass());
+        // Emit in hierarchy order to ensure superclass is defined when
+        // referenced
+        Collections.sort(needsSuperclass, new Comparator<JClassType>() {
+
+            @Override
+            public int compare(JClassType type1, JClassType type2) {
+                int depthDiff = getDepth(type1) - getDepth(type2);
+                if (depthDiff != 0) {
+                    return depthDiff;
+                } else {
+                    // Just something to get a stable compare
+                    return type1.getName().compareTo(type2.getName());
+                }
+            }
+
+            private int getDepth(JClassType type) {
+                int depth = 0;
+                while (type != null) {
+                    depth++;
+                    type = type.getSuperclass();
+                }
+                return depth;
+            }
+        });
+
+        for (JClassType jClassType : needsSuperclass) {
+            JClassType superclass = jClassType.getSuperclass();
+            while (superclass != null && !superclass.isPublic()) {
+                superclass = superclass.getSuperclass();
+            }
+            String classLiteralString;
+            if (superclass == null) {
+                classLiteralString = "null";
+            } else {
+                classLiteralString = getClassLiteralString(superclass);
+            }
+            w.println("store.setSuperClass(%s, %s);",
+                    getClassLiteralString(jClassType), classLiteralString);
+        }
+    }
+
     private void writeDelegateToWidget(TreeLogger logger,
             SplittingSourceWriter w, ConnectorBundle bundle) {
         Set<Property> needsDelegateToWidget = bundle.getNeedsDelegateToWidget();
@@ -378,64 +550,9 @@ public class ConnectorBundleLoaderFactory extends Generator {
         }
     }
 
-    private void writeGetters(TreeLogger logger, SplittingSourceWriter w,
+    private void writePropertyTypes(TreeLogger logger, SplittingSourceWriter w,
             ConnectorBundle bundle) {
-        Set<Property> properties = bundle.getNeedsSetter();
-        for (Property property : properties) {
-            w.print("store.setGetter(");
-            writeClassLiteral(w, property.getBeanType());
-            w.print(", \"");
-            w.print(escape(property.getName()));
-            w.println("\", new Invoker() {");
-            w.indent();
-
-            w.println("public Object invoke(Object bean, Object[] params) {");
-            w.indent();
-
-            property.writeGetterBody(logger, w, "bean");
-            w.println();
-
-            w.outdent();
-            w.println("}");
-
-            w.outdent();
-            w.println("});");
-
-            w.splitIfNeeded();
-        }
-    }
-
-    private void writeSetters(TreeLogger logger, SplittingSourceWriter w,
-            ConnectorBundle bundle) {
-        Set<Property> properties = bundle.getNeedsSetter();
-        for (Property property : properties) {
-            w.print("store.setSetter(");
-            writeClassLiteral(w, property.getBeanType());
-            w.print(", \"");
-            w.print(escape(property.getName()));
-            w.println("\", new Invoker() {");
-            w.indent();
-
-            w.println("public Object invoke(Object bean, Object[] params) {");
-            w.indent();
-
-            property.writeSetterBody(logger, w, "bean", "params[0]");
-
-            w.println("return null;");
-
-            w.outdent();
-            w.println("}");
-
-            w.outdent();
-            w.println("});");
-
-            w.splitIfNeeded();
-        }
-    }
-
-    private void writePropertyTypes(SplittingSourceWriter w,
-            ConnectorBundle bundle) {
-        Set<Property> properties = bundle.getNeedsType();
+        Set<Property> properties = bundle.getNeedsProperty();
         for (Property property : properties) {
             w.print("store.setPropertyType(");
             writeClassLiteral(w, property.getBeanType());
@@ -449,40 +566,7 @@ public class ConnectorBundleLoaderFactory extends Generator {
         }
     }
 
-    private void writeProperites(TreeLogger logger, SplittingSourceWriter w,
-            ConnectorBundle bundle) throws UnableToCompleteException {
-        Set<JClassType> needsPropertyListing = bundle.getNeedsPropertyListing();
-        for (JClassType type : needsPropertyListing) {
-            w.print("store.setProperties(");
-            writeClassLiteral(w, type);
-            w.print(", new String[] {");
-
-            Set<String> usedPropertyNames = new HashSet<String>();
-            Collection<Property> properties = bundle.getProperties(type);
-            for (Property property : properties) {
-                String name = property.getName();
-                if (!usedPropertyNames.add(name)) {
-                    logger.log(
-                            Type.ERROR,
-                            type.getQualifiedSourceName()
-                                    + " has multiple properties with the name "
-                                    + name
-                                    + ". This can happen if there are multiple setters with identical names exect casing.");
-                    throw new UnableToCompleteException();
-                }
-
-                w.print("\"");
-                w.print(name);
-                w.print("\", ");
-            }
-
-            w.println("});");
-
-            w.splitIfNeeded();
-        }
-    }
-
-    private void wirteDelayedInfo(SplittingSourceWriter w,
+    private void writeDelayedInfo(SplittingSourceWriter w,
             ConnectorBundle bundle) {
         Map<JClassType, Set<JMethod>> needsDelayedInfo = bundle
                 .getNeedsDelayedInfo();
index 4d6a7ff6d7c3b5a22c8c4db4632750d795eba307..0064a24aef2eeadbb97dc6272b01eddbe19ba0c9 100644 (file)
@@ -59,7 +59,7 @@ public class ConnectorBundle {
     private final Set<JType> needsSerializeSupport = new HashSet<JType>();
     private final Map<JType, GeneratedSerializer> serializers = new HashMap<JType, GeneratedSerializer>();
 
-    private final Set<JClassType> needsPropertyList = new HashSet<JClassType>();
+    private final Set<JClassType> needsSuperClass = new HashSet<JClassType>();
     private final Set<JClassType> needsGwtConstructor = new HashSet<JClassType>();
     private final Set<JClassType> visitedTypes = new HashSet<JClassType>();
     private final Set<JClassType> needsProxySupport = new HashSet<JClassType>();
@@ -70,9 +70,7 @@ public class ConnectorBundle {
     private final Map<JClassType, Set<JMethod>> needsParamTypes = new HashMap<JClassType, Set<JMethod>>();
     private final Map<JClassType, Set<JMethod>> needsDelayedInfo = new HashMap<JClassType, Set<JMethod>>();
 
-    private final Set<Property> needsSetter = new HashSet<Property>();
-    private final Set<Property> needsType = new HashSet<Property>();
-    private final Set<Property> needsGetter = new HashSet<Property>();
+    private final Set<Property> needsProperty = new HashSet<Property>();
     private final Set<Property> needsDelegateToWidget = new HashSet<Property>();
 
     private ConnectorBundle(String name, ConnectorBundle previousBundle,
@@ -246,16 +244,18 @@ public class ConnectorBundle {
 
             logger.log(Type.INFO, "Will serialize " + type + " as a bean");
 
-            setNeedsPropertyList(typeAsClass);
+            JClassType needsSuperClass = typeAsClass;
+            while (needsSuperClass != null) {
+                if (needsSuperClass.isPublic()) {
+                    setNeedsSuperclass(needsSuperClass);
+                }
+                needsSuperClass = needsSuperClass.getSuperclass();
+            }
 
             for (Property property : getProperties(typeAsClass)) {
                 setNeedsGwtConstructor(property.getBeanType());
-                setNeedsSetter(property);
 
-                // Getters needed for reading previous value that should be
-                // passed to sub encoder
-                setNeedsGetter(property);
-                setNeedsType(property);
+                setNeedsProperty(property);
 
                 JType propertyType = property.getPropertyType();
                 setNeedsSerialize(propertyType);
@@ -304,80 +304,42 @@ public class ConnectorBundle {
         return Collections.unmodifiableMap(serializers);
     }
 
-    private void setNeedsGetter(Property property) {
-        if (!isNeedsGetter(property)) {
-            needsGetter.add(property);
-        }
-    }
-
-    private boolean isNeedsGetter(Property property) {
-        if (needsGetter.contains(property)) {
-            return true;
-        } else {
-            return previousBundle != null
-                    && previousBundle.isNeedsGetter(property);
-        }
-    }
-
-    public Set<Property> getNeedsGetter() {
-        return Collections.unmodifiableSet(needsGetter);
-    }
-
-    private void setNeedsType(Property property) {
-        if (!isNeedsType(property)) {
-            needsType.add(property);
-        }
-    }
-
-    public Set<Property> getNeedsType() {
-        return Collections.unmodifiableSet(needsType);
-    }
-
-    private boolean isNeedsType(Property property) {
-        if (needsType.contains(property)) {
-            return true;
-        } else {
-            return previousBundle != null
-                    && previousBundle.isNeedsType(property);
-        }
-    }
-
-    public void setNeedsSetter(Property property) {
-        if (!isNeedsSetter(property)) {
-            needsSetter.add(property);
+    private void setNeedsSuperclass(JClassType typeAsClass) {
+        if (!isNeedsSuperClass(typeAsClass)) {
+            needsSuperClass.add(typeAsClass);
         }
     }
 
-    private boolean isNeedsSetter(Property property) {
-        if (needsSetter.contains(property)) {
+    private boolean isNeedsSuperClass(JClassType typeAsClass) {
+        if (needsSuperClass.contains(typeAsClass)) {
             return true;
         } else {
             return previousBundle != null
-                    && previousBundle.isNeedsSetter(property);
+                    && previousBundle.isNeedsSuperClass(typeAsClass);
         }
     }
 
-    public Set<Property> getNeedsSetter() {
-        return Collections.unmodifiableSet(needsSetter);
+    public Set<JClassType> getNeedsSuperclass() {
+        return Collections.unmodifiableSet(needsSuperClass);
     }
 
-    private void setNeedsPropertyList(JClassType type) {
-        if (!isNeedsPropertyList(type)) {
-            needsPropertyList.add(type);
+    private void setNeedsProperty(Property property) {
+        if (!isNeedsProperty(property)) {
+            needsProperty.add(property);
         }
     }
 
-    private boolean isNeedsPropertyList(JClassType type) {
-        if (needsPropertyList.contains(type)) {
+    private boolean isNeedsProperty(Property property) {
+        if (needsProperty.contains(property)) {
             return true;
         } else {
             return previousBundle != null
-                    && previousBundle.isNeedsPropertyList(type);
+                    && previousBundle.isNeedsProperty(property);
         }
     }
 
-    public Set<JClassType> getNeedsPropertyListing() {
-        return Collections.unmodifiableSet(needsPropertyList);
+    public Set<Property> getNeedsProperty() {
+        return Collections.unmodifiableSet(needsProperty);
     }
 
     public Collection<Property> getProperties(JClassType type) {
@@ -623,4 +585,4 @@ public class ConnectorBundle {
         return Collections.unmodifiableSet(needsDelegateToWidget);
     }
 
-}
\ No newline at end of file
+}
index 86b82608852aaefaca68d813a3a40f8cd0b99f05..e9ff4587fb1f4d2692c8920f1f8232e925894756 100644 (file)
@@ -37,19 +37,26 @@ public class FieldProperty extends Property {
         this.field = field;
     }
 
+    @Override
+    public boolean hasAccessorMethods() {
+        return true;
+    }
+
     @Override
     public void writeSetterBody(TreeLogger logger, SourceWriter w,
             String beanVariable, String valueVariable) {
-        w.print("((%s) %s).%s = (%s)%s;", getBeanType()
-                .getQualifiedSourceName(), beanVariable, getName(),
-                getUnboxedPropertyTypeName(), valueVariable);
+        w.println("%s.@%s::%s = %s;", beanVariable, getBeanType()
+                .getQualifiedSourceName(), getName(), unboxValue(valueVariable));
     }
 
     @Override
     public void writeGetterBody(TreeLogger logger, SourceWriter w,
             String beanVariable) {
-        w.print("return ((%s) %s).%s;", getBeanType().getQualifiedSourceName(),
-                beanVariable, getName());
+        String value = String.format("%s.@%s::%s", beanVariable, getBeanType()
+                .getQualifiedSourceName(), getName());
+        w.print("return ");
+        w.print(boxValue(value));
+        w.println(";");
     }
 
     public static Collection<FieldProperty> findProperties(JClassType type) {
@@ -57,7 +64,7 @@ public class FieldProperty extends Property {
 
         List<JField> fields = getPublicFields(type);
         for (JField field : fields) {
-            properties.add(new FieldProperty(type, field));
+            properties.add(new FieldProperty(field.getEnclosingType(), field));
         }
 
         return properties;
index 3c317e033ed54699c6537d1ac517d24363a5f294..1d9deef26526e59a1ccc4c41e608196ba4c381ac 100644 (file)
@@ -19,7 +19,9 @@ package com.vaadin.server.widgetsetutils.metadata;
 import java.lang.annotation.Annotation;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.typeinfo.JClassType;
@@ -31,18 +33,29 @@ public class MethodProperty extends Property {
 
     private final JMethod setter;
 
-    private MethodProperty(JClassType beanType, JMethod setter) {
+    private final String getter;
+
+    private MethodProperty(JClassType beanType, JMethod setter, String getter) {
         super(getTransportFieldName(setter), beanType, setter
                 .getParameterTypes()[0]);
         this.setter = setter;
+        this.getter = getter;
+    }
+
+    @Override
+    public boolean hasAccessorMethods() {
+        return getter != null;
     }
 
     public static Collection<MethodProperty> findProperties(JClassType type) {
         Collection<MethodProperty> properties = new ArrayList<MethodProperty>();
 
-        List<JMethod> setters = getSetters(type);
+        Set<String> getters = new HashSet<String>();
+        List<JMethod> setters = getSetters(type, getters);
         for (JMethod setter : setters) {
-            properties.add(new MethodProperty(type, setter));
+            String getter = findGetter(type, setter);
+            properties.add(new MethodProperty(setter.getEnclosingType(),
+                    setter, getters.contains(getter) ? getter : null));
         }
 
         return properties;
@@ -53,9 +66,12 @@ public class MethodProperty extends Property {
      * 
      * @param beanType
      *            The type to check
+     * @param getters
+     *            Set that will be filled with names of getters.
      * @return A list of setter methods from the class and its parents
      */
-    private static List<JMethod> getSetters(JClassType beanType) {
+    private static List<JMethod> getSetters(JClassType beanType,
+            Set<String> getters) {
         List<JMethod> setterMethods = new ArrayList<JMethod>();
 
         while (beanType != null
@@ -63,13 +79,19 @@ public class MethodProperty extends Property {
                         Object.class.getName())) {
             for (JMethod method : beanType.getMethods()) {
                 // Process all setters that have corresponding fields
-                if (!method.isPublic() || method.isStatic()
-                        || !method.getName().startsWith("set")
-                        || method.getParameterTypes().length != 1) {
-                    // Not setter, skip to next method
+                if (!method.isPublic() || method.isStatic()) {
+                    // Not getter/setter, skip to next method
                     continue;
                 }
-                setterMethods.add(method);
+                String methodName = method.getName();
+                if (methodName.startsWith("set")
+                        && method.getParameterTypes().length == 1) {
+                    setterMethods.add(method);
+                } else if (method.getParameterTypes().length == 0
+                        && methodName.startsWith("is")
+                        || methodName.startsWith("get")) {
+                    getters.add(methodName);
+                }
             }
             beanType = beanType.getSuperclass();
         }
@@ -78,34 +100,26 @@ public class MethodProperty extends Property {
     }
 
     @Override
-    public void writeSetterBody(TreeLogger logger, SourceWriter w,
-            String beanVariable, String valueVariable) {
-        w.print("((");
-        w.print(getBeanType().getQualifiedSourceName());
-        w.print(") ");
-        w.print(beanVariable);
-        w.print(").");
-        w.print(setter.getName());
-        w.print("((");
-        w.print(getUnboxedPropertyTypeName());
-        w.print(") ");
-        w.print(valueVariable);
-        w.println(");");
+    public void writeGetterBody(TreeLogger logger, SourceWriter w,
+            String beanVariable) {
+        String value = String.format("%s.@%s::%s()()", beanVariable,
+                getBeanType().getQualifiedSourceName(), getter);
+        w.print("return ");
+        w.print(boxValue(value));
+        w.println(";");
     }
 
     @Override
-    public void writeGetterBody(TreeLogger logger, SourceWriter w,
-            String beanVariable) {
-        w.print("return ((");
-        w.print(getBeanType().getQualifiedSourceName());
-        w.print(") ");
-        w.print(beanVariable);
-        w.print(").");
-        w.print(findGetter(getBeanType(), setter));
-        w.print("();");
+    public void writeSetterBody(TreeLogger logger, SourceWriter w,
+            String beanVariable, String valueVariable) {
+        w.println("%s.@%s::%s(%s)(%s);", beanVariable, getBeanType()
+                .getQualifiedSourceName(), setter.getName(), setter
+                .getParameterTypes()[0].getJNISignature(),
+                unboxValue(valueVariable));
+
     }
 
-    private String findGetter(JClassType beanType, JMethod setterMethod) {
+    private static String findGetter(JClassType beanType, JMethod setterMethod) {
         JType setterParameterType = setterMethod.getParameterTypes()[0];
         String fieldName = setterMethod.getName().substring(3);
         if (setterParameterType.getQualifiedSourceName().equals(
index 02aad7bdf22ba49ec234072af8a60045e61a83fe..381af23b427741aaee519261679f1f7f7aab3c4a 100644 (file)
@@ -53,6 +53,28 @@ public abstract class Property {
         }
     }
 
+    public String boxValue(String codeSnippet) {
+        JPrimitiveType primitive = propertyType.isPrimitive();
+        if (primitive == null) {
+            return codeSnippet;
+        } else {
+            return String.format("@%s::valueOf(%s)(%s)",
+                    primitive.getQualifiedBoxedSourceName(),
+                    propertyType.getJNISignature(), codeSnippet);
+        }
+    }
+
+    public String unboxValue(String codeSnippet) {
+        JPrimitiveType primitive = propertyType.isPrimitive();
+        if (primitive == null) {
+            return codeSnippet;
+        } else {
+            return String.format("%s.@%s::%sValue()()", codeSnippet,
+                    primitive.getQualifiedBoxedSourceName(),
+                    primitive.getSimpleSourceName());
+        }
+    }
+
     public JClassType getBeanType() {
         return beanType;
     }
@@ -63,6 +85,8 @@ public abstract class Property {
     public abstract void writeGetterBody(TreeLogger logger, SourceWriter w,
             String beanVariable);
 
+    public abstract boolean hasAccessorMethods();
+
     @Override
     public boolean equals(Object obj) {
         if (this == obj) {
index f1a9fa1ee78d7e0a5ec7ab13f140a2595cb5ca19..8148010b549587226e459d41eab2db31f3985550 100644 (file)
  */
 package com.vaadin.client.metadata;
 
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import com.google.gwt.core.shared.GWT;
+import com.vaadin.client.FastStringMap;
 import com.vaadin.client.metadata.AsyncBundleLoader.State;
 
 public abstract class ConnectorBundleLoader {
@@ -28,8 +27,9 @@ public abstract class ConnectorBundleLoader {
 
     private static ConnectorBundleLoader impl;
 
-    private Map<String, AsyncBundleLoader> asyncBlockLoaders = new HashMap<String, AsyncBundleLoader>();
-    private Map<String, String> identifierToBundle = new HashMap<String, String>();
+    private FastStringMap<AsyncBundleLoader> asyncBlockLoaders = FastStringMap
+            .create();
+    private FastStringMap<String> identifierToBundle = FastStringMap.create();
 
     private final TypeDataStore datStore = new TypeDataStore();
 
index 2e0ea49c88df857a45eb323dfefa2760c53527c9..64fbb79ca12a6b51d1306d1c18f2bd5681f05bec 100644 (file)
@@ -30,11 +30,11 @@ public class Property {
     }
 
     public Object getValue(Object bean) throws NoDataException {
-        return TypeDataStore.getGetter(this).invoke(bean);
+        return TypeDataStore.getValue(this, bean);
     }
 
     public void setValue(Object bean, Object value) throws NoDataException {
-        TypeDataStore.getSetter(this).invoke(bean, value);
+        TypeDataStore.setValue(this, bean, value);
     }
 
     public String getDelegateToWidgetMethodName() {
@@ -50,6 +50,10 @@ public class Property {
         return TypeDataStore.getType(this);
     }
 
+    public Type getBeanType() {
+        return bean;
+    }
+
     /**
      * The unique signature used to identify this property. The structure of the
      * returned string may change without notice and should not be used for any
index 649f018f95b78f994560202d1e5df138c22fd451..a3939b7994fd232d8617c8582a14eff1cd9a2742 100644 (file)
@@ -34,8 +34,6 @@ public class TypeDataStore {
             .create();
     private final FastStringMap<ProxyHandler> proxyHandlers = FastStringMap
             .create();
-    private final FastStringMap<JsArrayObject<Property>> properties = FastStringMap
-            .create();
     private final FastStringMap<JsArrayString> delegateToWidgetProperties = FastStringMap
             .create();
 
@@ -46,12 +44,11 @@ public class TypeDataStore {
     private final FastStringMap<Invoker> invokers = FastStringMap.create();
     private final FastStringMap<Type[]> paramTypes = FastStringMap.create();
 
-    private final FastStringMap<Type> propertyTypes = FastStringMap.create();
-    private final FastStringMap<Invoker> setters = FastStringMap.create();
-    private final FastStringMap<Invoker> getters = FastStringMap.create();
     private final FastStringMap<String> delegateToWidget = FastStringMap
             .create();
 
+    private final JavaScriptObject jsTypeData = JavaScriptObject.createObject();
+
     public static TypeDataStore get() {
         return ConnectorBundleLoader.get().getTypeDataStore();
     }
@@ -117,19 +114,10 @@ public class TypeDataStore {
         return invoker;
     }
 
-    public static Invoker getGetter(Property property) throws NoDataException {
-        Invoker getter = get().getters.get(property.getSignature());
-        if (getter == null) {
-            throw new NoDataException("There is no getter for "
-                    + property.getSignature());
-        }
-
-        return getter;
-    }
-
-    public void setGetter(Class<?> clazz, String propertyName, Invoker invoker) {
-        getters.put(new Property(getType(clazz), propertyName).getSignature(),
-                invoker);
+    public static Object getValue(Property property, Object target)
+            throws NoDataException {
+        return getJsPropertyValue(get().jsTypeData, property.getBeanType()
+                .getBaseTypeName(), property.getName(), target);
     }
 
     public static String getDelegateToWidget(Property property) {
@@ -243,51 +231,31 @@ public class TypeDataStore {
 
     public static JsArrayObject<Property> getPropertiesAsArray(Type type)
             throws NoDataException {
-        JsArrayObject<Property> properties = get().properties.get(type
-                .getSignature());
-        if (properties == null) {
-            throw new NoDataException("No property list for "
-                    + type.getSignature());
-        }
-        return properties;
-    }
+        JsArrayString names = getJsPropertyNames(get().jsTypeData,
+                type.getBaseTypeName());
 
-    public void setProperties(Class<?> clazz, String[] propertyNames) {
+        // Create Property instances for each property name
         JsArrayObject<Property> properties = JavaScriptObject.createArray()
                 .cast();
-        Type type = getType(clazz);
-        for (String name : propertyNames) {
-            properties.add(new Property(type, name));
+        for (int i = 0; i < names.length(); i++) {
+            properties.add(new Property(type, names.get(i)));
         }
-        this.properties.put(type.getSignature(), properties);
-    }
 
-    public static Type getType(Property property) throws NoDataException {
-        Type type = get().propertyTypes.get(property.getSignature());
-        if (type == null) {
-            throw new NoDataException("No return type for "
-                    + property.getSignature());
-        }
-        return type;
+        return properties;
     }
 
-    public void setPropertyType(Class<?> clazz, String propertName, Type type) {
-        propertyTypes.put(
-                new Property(getType(clazz), propertName).getSignature(), type);
+    public static Type getType(Property property) throws NoDataException {
+        return getJsPropertyType(get().jsTypeData, property.getBeanType()
+                .getBaseTypeName(), property.getName());
     }
 
-    public static Invoker getSetter(Property property) throws NoDataException {
-        Invoker setter = get().setters.get(property.getSignature());
-        if (setter == null) {
-            throw new NoDataException("No setter for "
-                    + property.getSignature());
-        }
-        return setter;
+    public void setPropertyType(Class<?> clazz, String propertyName, Type type) {
+        setJsPropertyType(jsTypeData, clazz.getName(), propertyName, type);
     }
 
-    public void setSetter(Class<?> clazz, String propertyName, Invoker setter) {
-        setters.put(new Property(getType(clazz), propertyName).getSignature(),
-                setter);
+    public static void setValue(Property property, Object target, Object value) {
+        setJsPropertyValue(get().jsTypeData, property.getBeanType()
+                .getBaseTypeName(), property.getName(), target, value);
     }
 
     public void setSerializerFactory(Class<?> clazz, Invoker factory) {
@@ -304,6 +272,99 @@ public class TypeDataStore {
     }
 
     public static boolean hasProperties(Type type) {
-        return get().properties.containsKey(type.getSignature());
+        return hasJsProperties(get().jsTypeData, type.getBaseTypeName());
+    }
+
+    public void setSuperClass(Class<?> baseClass, Class<?> superClass) {
+        String superClassName = superClass == null ? null : superClass
+                .getName();
+        setSuperClass(jsTypeData, baseClass.getName(), superClassName);
+    }
+
+    public void setPropertyData(Class<?> type, String propertyName,
+            JavaScriptObject propertyData) {
+        setPropertyData(jsTypeData, type.getName(), propertyName, propertyData);
     }
+
+    private static native void setPropertyData(JavaScriptObject typeData,
+            String className, String propertyName, JavaScriptObject propertyData)
+    /*-{
+        typeData[className][propertyName] = propertyData;
+    }-*/;
+
+    /*
+     * This method sets up prototypes chain for <code>baseClassName</code>.
+     * Precondition is : <code>superClassName</code> had to be handled before
+     * its child <code>baseClassName</code>.
+     * 
+     * It makes all properties defined in the <code>superClassName</code>
+     * available for <code>baseClassName</code> as well.
+     */
+    private static native void setSuperClass(JavaScriptObject typeData,
+            String baseClassName, String superClassName)
+    /*-{
+        var parentType = typeData[superClassName];
+        if (parentType !== undefined ){
+            var ctor = function () {};
+            ctor.prototype = parentType;
+            typeData[baseClassName] = new ctor;
+        }
+        else {
+            typeData[baseClassName] = {};
+        } 
+    }-*/;
+
+    private static native boolean hasGetter(JavaScriptObject typeData,
+            String beanName, String propertyName)
+    /*-{
+        return typeData[beanName][propertyName].getter !== undefined;
+    }-*/;
+
+    private static native boolean hasSetter(JavaScriptObject typeData,
+            String beanName, String propertyName)
+    /*-{
+        return typeData[beanName][propertyName].setter !== undefined;
+    }-*/;
+
+    private static native Object getJsPropertyValue(JavaScriptObject typeData,
+            String beanName, String propertyName, Object beanInstance)
+    /*-{
+        return typeData[beanName][propertyName].getter(beanInstance);
+    }-*/;
+
+    private static native void setJsPropertyValue(JavaScriptObject typeData,
+            String beanName, String propertyName, Object beanInstance,
+            Object value)
+    /*-{
+        typeData[beanName][propertyName].setter(beanInstance, value);
+    }-*/;
+
+    private static native Type getJsPropertyType(JavaScriptObject typeData,
+            String beanName, String propertyName)
+    /*-{
+        return typeData[beanName][propertyName].type;
+    }-*/;
+
+    private static native void setJsPropertyType(JavaScriptObject typeData,
+            String beanName, String propertyName, Type type)
+    /*-{
+        typeData[beanName][propertyName].type = type;
+    }-*/;
+
+    private static native JsArrayString getJsPropertyNames(
+            JavaScriptObject typeData, String beanName)
+    /*-{
+        var names = [];
+        for(var name in typeData[beanName]) {
+            names.push(name);
+        }
+        return names;
+    }-*/;
+
+    private static native boolean hasJsProperties(JavaScriptObject typeData,
+            String beanName)
+    /*-{
+        return typeData[beanName] !== undefined ;
+    }-*/;
+
 }