From: denisanisimov Date: Tue, 4 Feb 2014 11:11:39 +0000 (+0200) Subject: Reduce generated ConnectorBundleLoaderImpl size. (#9379) X-Git-Tag: 7.2.0.beta1~163 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=5592f056be51e2d18498c067fa5232963677d32e;p=vaadin-framework.git Reduce generated ConnectorBundleLoaderImpl size. (#9379) Change-Id: I49411e6893f3adc1c41cc690aca35cd919769625 --- diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java b/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java index f8aa586064..1c06cea3fa 100644 --- a/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java +++ b/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java @@ -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 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(); + 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 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 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 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> definedProperties = new HashMap>(); + + for (Property property : bundle.getNeedsProperty()) { + JClassType beanType = property.getBeanType(); + Set usedPropertyNames = definedProperties.get(beanType); + if (usedPropertyNames == null) { + usedPropertyNames = new HashSet(); + 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 printJsBundleData(TreeLogger logger, SourceWriter w, + ConnectorBundle bundle, String methodName) { + SplittingSourceWriter writer = new SplittingSourceWriter(w, methodName, + 30000); + Set 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 needsSuperclass = new ArrayList( + bundle.getNeedsSuperclass()); + // Emit in hierarchy order to ensure superclass is defined when + // referenced + Collections.sort(needsSuperclass, new Comparator() { + + @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 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 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 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 properties = bundle.getNeedsType(); + Set 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 needsPropertyListing = bundle.getNeedsPropertyListing(); - for (JClassType type : needsPropertyListing) { - w.print("store.setProperties("); - writeClassLiteral(w, type); - w.print(", new String[] {"); - - Set usedPropertyNames = new HashSet(); - Collection 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> needsDelayedInfo = bundle .getNeedsDelayedInfo(); diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java index 4d6a7ff6d7..0064a24aef 100644 --- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java +++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java @@ -59,7 +59,7 @@ public class ConnectorBundle { private final Set needsSerializeSupport = new HashSet(); private final Map serializers = new HashMap(); - private final Set needsPropertyList = new HashSet(); + private final Set needsSuperClass = new HashSet(); private final Set needsGwtConstructor = new HashSet(); private final Set visitedTypes = new HashSet(); private final Set needsProxySupport = new HashSet(); @@ -70,9 +70,7 @@ public class ConnectorBundle { private final Map> needsParamTypes = new HashMap>(); private final Map> needsDelayedInfo = new HashMap>(); - private final Set needsSetter = new HashSet(); - private final Set needsType = new HashSet(); - private final Set needsGetter = new HashSet(); + private final Set needsProperty = new HashSet(); private final Set needsDelegateToWidget = new HashSet(); 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 getNeedsGetter() { - return Collections.unmodifiableSet(needsGetter); - } - - private void setNeedsType(Property property) { - if (!isNeedsType(property)) { - needsType.add(property); - } - } - - public Set 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 getNeedsSetter() { - return Collections.unmodifiableSet(needsSetter); + public Set 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 getNeedsPropertyListing() { - return Collections.unmodifiableSet(needsPropertyList); + public Set getNeedsProperty() { + return Collections.unmodifiableSet(needsProperty); } public Collection getProperties(JClassType type) { @@ -623,4 +585,4 @@ public class ConnectorBundle { return Collections.unmodifiableSet(needsDelegateToWidget); } -} \ No newline at end of file +} diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/FieldProperty.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/FieldProperty.java index 86b8260885..e9ff4587fb 100644 --- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/FieldProperty.java +++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/FieldProperty.java @@ -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 findProperties(JClassType type) { @@ -57,7 +64,7 @@ public class FieldProperty extends Property { List fields = getPublicFields(type); for (JField field : fields) { - properties.add(new FieldProperty(type, field)); + properties.add(new FieldProperty(field.getEnclosingType(), field)); } return properties; diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/MethodProperty.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/MethodProperty.java index 3c317e033e..1d9deef265 100644 --- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/MethodProperty.java +++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/MethodProperty.java @@ -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 findProperties(JClassType type) { Collection properties = new ArrayList(); - List setters = getSetters(type); + Set getters = new HashSet(); + List 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 getSetters(JClassType beanType) { + private static List getSetters(JClassType beanType, + Set getters) { List setterMethods = new ArrayList(); 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( diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/Property.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/Property.java index 02aad7bdf2..381af23b42 100644 --- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/Property.java +++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/Property.java @@ -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) { diff --git a/client/src/com/vaadin/client/metadata/ConnectorBundleLoader.java b/client/src/com/vaadin/client/metadata/ConnectorBundleLoader.java index f1a9fa1ee7..8148010b54 100644 --- a/client/src/com/vaadin/client/metadata/ConnectorBundleLoader.java +++ b/client/src/com/vaadin/client/metadata/ConnectorBundleLoader.java @@ -15,11 +15,10 @@ */ 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 asyncBlockLoaders = new HashMap(); - private Map identifierToBundle = new HashMap(); + private FastStringMap asyncBlockLoaders = FastStringMap + .create(); + private FastStringMap identifierToBundle = FastStringMap.create(); private final TypeDataStore datStore = new TypeDataStore(); diff --git a/client/src/com/vaadin/client/metadata/Property.java b/client/src/com/vaadin/client/metadata/Property.java index 2e0ea49c88..64fbb79ca1 100644 --- a/client/src/com/vaadin/client/metadata/Property.java +++ b/client/src/com/vaadin/client/metadata/Property.java @@ -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 diff --git a/client/src/com/vaadin/client/metadata/TypeDataStore.java b/client/src/com/vaadin/client/metadata/TypeDataStore.java index 649f018f95..a3939b7994 100644 --- a/client/src/com/vaadin/client/metadata/TypeDataStore.java +++ b/client/src/com/vaadin/client/metadata/TypeDataStore.java @@ -34,8 +34,6 @@ public class TypeDataStore { .create(); private final FastStringMap proxyHandlers = FastStringMap .create(); - private final FastStringMap> properties = FastStringMap - .create(); private final FastStringMap delegateToWidgetProperties = FastStringMap .create(); @@ -46,12 +44,11 @@ public class TypeDataStore { private final FastStringMap invokers = FastStringMap.create(); private final FastStringMap paramTypes = FastStringMap.create(); - private final FastStringMap propertyTypes = FastStringMap.create(); - private final FastStringMap setters = FastStringMap.create(); - private final FastStringMap getters = FastStringMap.create(); private final FastStringMap 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 getPropertiesAsArray(Type type) throws NoDataException { - JsArrayObject 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 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 baseClassName. + * Precondition is : superClassName had to be handled before + * its child baseClassName. + * + * It makes all properties defined in the superClassName + * available for baseClassName 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 ; + }-*/; + }