Browse Source

Reduce generated ConnectorBundleLoaderImpl size. (#9379)

Change-Id: I49411e6893f3adc1c41cc690aca35cd919769625
tags/7.2.0.beta1
denisanisimov 10 years ago
parent
commit
5592f056be

+ 186
- 102
client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java View 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();

+ 27
- 65
client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java View 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);
}

}
}

+ 13
- 6
client-compiler/src/com/vaadin/server/widgetsetutils/metadata/FieldProperty.java View 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;

+ 46
- 32
client-compiler/src/com/vaadin/server/widgetsetutils/metadata/MethodProperty.java View 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(

+ 24
- 0
client-compiler/src/com/vaadin/server/widgetsetutils/metadata/Property.java View 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) {

+ 4
- 4
client/src/com/vaadin/client/metadata/ConnectorBundleLoader.java View File

@@ -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<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();


+ 6
- 2
client/src/com/vaadin/client/metadata/Property.java View 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

+ 114
- 53
client/src/com/vaadin/client/metadata/TypeDataStore.java View 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 ;
}-*/;

}

Loading…
Cancel
Save