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;
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;
this.target = target;
this.baseName = baseName;
this.splitSize = splitSize;
+ methodNames = new ArrayList<String>();
+ methodNames.add(baseName);
}
@Override
}
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
w.indent();
for (ConnectorBundle bundle : bundles) {
+ detectBadProperties(bundle, logger);
+
String name = bundle.getName();
boolean isEager = name
.equals(ConnectorBundleLoader.EAGER_BUNDLE_NAME);
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();
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();
}
}
- 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());
}
}
- 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();
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>();
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,
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);
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) {
return Collections.unmodifiableSet(needsDelegateToWidget);
}
-}
\ No newline at end of file
+}
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) {
List<JField> fields = getPublicFields(type);
for (JField field : fields) {
- properties.add(new FieldProperty(type, field));
+ properties.add(new FieldProperty(field.getEnclosingType(), field));
}
return properties;
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;
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;
*
* @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
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();
}
}
@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(
}
}
+ 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;
}
public abstract void writeGetterBody(TreeLogger logger, SourceWriter w,
String beanVariable);
+ public abstract boolean hasAccessorMethods();
+
@Override
public boolean equals(Object obj) {
if (this == obj) {
*/
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 {
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();
}
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() {
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
.create();
private final FastStringMap<ProxyHandler> proxyHandlers = FastStringMap
.create();
- private final FastStringMap<JsArrayObject<Property>> properties = FastStringMap
- .create();
private final FastStringMap<JsArrayString> delegateToWidgetProperties = FastStringMap
.create();
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();
}
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) {
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) {
}
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 ;
+ }-*/;
+
}