summaryrefslogtreecommitdiffstats
path: root/client-compiler
diff options
context:
space:
mode:
authorLeif Åstrand <leif@vaadin.com>2014-03-27 11:14:55 +0200
committerVaadin Code Review <review@vaadin.com>2014-04-01 08:15:56 +0000
commit7bfb2347ad32187444c194e7ebadae6a6d3597ca (patch)
treec94081d4cb9d2eba433c4cec3ddbcc27da57c643 /client-compiler
parenta636bb70c20277228468345017a2f8d42d39857c (diff)
downloadvaadin-framework-7bfb2347ad32187444c194e7ebadae6a6d3597ca.tar.gz
vaadin-framework-7bfb2347ad32187444c194e7ebadae6a6d3597ca.zip
Implement @OnStateChange (#12958)
Change-Id: I8ea2b781fab42458bf55a751c1229e391365e965
Diffstat (limited to 'client-compiler')
-rw-r--r--client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java91
-rw-r--r--client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java50
-rw-r--r--client-compiler/src/com/vaadin/server/widgetsetutils/metadata/OnStateChangeVisitor.java54
-rw-r--r--client-compiler/src/com/vaadin/server/widgetsetutils/metadata/StateInitVisitor.java3
-rw-r--r--client-compiler/src/com/vaadin/server/widgetsetutils/metadata/TypeVisitor.java25
-rw-r--r--client-compiler/src/com/vaadin/server/widgetsetutils/metadata/WidgetInitVisitor.java15
6 files changed, 201 insertions, 37 deletions
diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java b/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java
index edbf5e260c..9b00142534 100644
--- a/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java
+++ b/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java
@@ -46,8 +46,10 @@ import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.vaadin.client.JsArrayObject;
import com.vaadin.client.ServerConnector;
+import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.metadata.ConnectorBundleLoader;
import com.vaadin.client.metadata.InvokationHandler;
+import com.vaadin.client.metadata.OnStateChangeMethod;
import com.vaadin.client.metadata.ProxyHandler;
import com.vaadin.client.metadata.TypeData;
import com.vaadin.client.metadata.TypeDataStore;
@@ -56,6 +58,7 @@ import com.vaadin.server.widgetsetutils.metadata.ClientRpcVisitor;
import com.vaadin.server.widgetsetutils.metadata.ConnectorBundle;
import com.vaadin.server.widgetsetutils.metadata.ConnectorInitVisitor;
import com.vaadin.server.widgetsetutils.metadata.GeneratedSerializer;
+import com.vaadin.server.widgetsetutils.metadata.OnStateChangeVisitor;
import com.vaadin.server.widgetsetutils.metadata.Property;
import com.vaadin.server.widgetsetutils.metadata.ServerRpcVisitor;
import com.vaadin.server.widgetsetutils.metadata.StateInitVisitor;
@@ -463,6 +466,92 @@ public class ConnectorBundleLoaderFactory extends Generator {
writePropertyTypes(logger, w, bundle);
writeSerializers(logger, w, bundle);
writeDelegateToWidget(logger, w, bundle);
+ writeOnStateChangeHandlers(logger, w, bundle);
+ }
+
+ private void writeOnStateChangeHandlers(TreeLogger logger,
+ SplittingSourceWriter w, ConnectorBundle bundle)
+ throws UnableToCompleteException {
+ Map<JClassType, Set<JMethod>> needsOnStateChangeHandler = bundle
+ .getNeedsOnStateChangeHandler();
+ for (Entry<JClassType, Set<JMethod>> entry : needsOnStateChangeHandler
+ .entrySet()) {
+ JClassType connector = entry.getKey();
+
+ TreeLogger typeLogger = logger.branch(
+ Type.DEBUG,
+ "Generating @OnStateChange support for "
+ + connector.getName());
+
+ // Build map to speed up error checking
+ HashMap<String, Property> stateProperties = new HashMap<String, Property>();
+ JClassType stateType = ConnectorBundle
+ .findInheritedMethod(connector, "getState").getReturnType()
+ .isClassOrInterface();
+ for (Property property : bundle.getProperties(stateType)) {
+ stateProperties.put(property.getName(), property);
+ }
+
+ for (JMethod method : entry.getValue()) {
+ TreeLogger methodLogger = typeLogger.branch(Type.DEBUG,
+ "Processing method " + method.getName());
+
+ if (method.isPublic() || method.isProtected()) {
+ methodLogger
+ .log(Type.ERROR,
+ "@OnStateChange is only supported for methods with private or default visibility.");
+ throw new UnableToCompleteException();
+ }
+
+ OnStateChange onStateChange = method
+ .getAnnotation(OnStateChange.class);
+
+ String[] properties = onStateChange.value();
+
+ if (properties.length == 0) {
+ methodLogger.log(Type.ERROR,
+ "There are no properties to listen to");
+ throw new UnableToCompleteException();
+ }
+
+ // Verify that all properties do exist
+ for (String propertyName : properties) {
+ if (!stateProperties.containsKey(propertyName)) {
+ methodLogger.log(Type.ERROR,
+ "State class has no property named "
+ + propertyName);
+ throw new UnableToCompleteException();
+ }
+ }
+
+ if (method.getParameters().length != 0) {
+ methodLogger.log(Type.ERROR,
+ "Method should accept zero parameters");
+ throw new UnableToCompleteException();
+ }
+
+ // new OnStateChangeMethod(Class declaringClass, String
+ // methodName, String[], properties)
+ w.print("store.addOnStateChangeMethod(%s, new %s(",
+ getClassLiteralString(connector),
+ OnStateChangeMethod.class.getName());
+ if (!connector.equals(method.getEnclosingType())) {
+ w.print("%s, ",
+ getClassLiteralString(method.getEnclosingType()));
+ }
+ w.print("\"%s\", ", method.getName());
+
+ w.print("new String[] {");
+ for (String propertyName : properties) {
+ w.print("\"%s\", ", propertyName);
+ }
+ w.print("}");
+
+ w.println("));");
+
+ w.splitIfNeeded();
+ }
+ }
}
private void writeSuperClasses(SplittingSourceWriter w,
@@ -1109,7 +1198,7 @@ public class ConnectorBundleLoaderFactory extends Generator {
List<TypeVisitor> visitors = Arrays.<TypeVisitor> asList(
new ConnectorInitVisitor(), new StateInitVisitor(),
new WidgetInitVisitor(), new ClientRpcVisitor(),
- new ServerRpcVisitor());
+ new ServerRpcVisitor(), new OnStateChangeVisitor());
for (TypeVisitor typeVisitor : visitors) {
typeVisitor.init(oracle);
}
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 0064a24aef..f762a484b7 100644
--- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java
+++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java
@@ -69,6 +69,7 @@ public class ConnectorBundle {
private final Map<JClassType, Set<JMethod>> needsInvoker = new HashMap<JClassType, Set<JMethod>>();
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 Map<JClassType, Set<JMethod>> needsOnStateChange = new HashMap<JClassType, Set<JMethod>>();
private final Set<Property> needsProperty = new HashSet<Property>();
private final Set<Property> needsDelegateToWidget = new HashSet<Property>();
@@ -199,7 +200,7 @@ public class ConnectorBundle {
JType type = iterator.next();
iterator.remove();
- if (hasSserializeSupport(type)) {
+ if (hasSerializeSupport(type)) {
continue;
}
@@ -516,7 +517,7 @@ public class ConnectorBundle {
}
public void setNeedsSerialize(JType type) {
- if (!hasSserializeSupport(type)) {
+ if (!hasSerializeSupport(type)) {
needsSerializeSupport.add(type);
}
}
@@ -557,12 +558,12 @@ public class ConnectorBundle {
return false;
}
- private boolean hasSserializeSupport(JType type) {
+ private boolean hasSerializeSupport(JType type) {
if (hasSerializeSupport.contains(type)) {
return true;
} else {
return previousBundle != null
- && previousBundle.hasSserializeSupport(type);
+ && previousBundle.hasSerializeSupport(type);
}
}
@@ -585,4 +586,45 @@ public class ConnectorBundle {
return Collections.unmodifiableSet(needsDelegateToWidget);
}
+ public void setNeedsOnStateChangeHandler(JClassType type, JMethod method) {
+ if (!isNeedsOnStateChangeHandler(type, method)) {
+ addMapping(needsOnStateChange, type, method);
+ }
+ }
+
+ private boolean isNeedsOnStateChangeHandler(JClassType type, JMethod method) {
+ if (hasMapping(needsOnStateChange, type, method)) {
+ return true;
+ } else {
+ return previousBundle != null
+ && previousBundle.isNeedsOnStateChangeHandler(type, method);
+ }
+ }
+
+ public Map<JClassType, Set<JMethod>> getNeedsOnStateChangeHandler() {
+ return Collections.unmodifiableMap(needsOnStateChange);
+ }
+
+ public static JMethod findInheritedMethod(JClassType type,
+ String methodName, JType... params) {
+
+ JClassType currentType = type;
+ while (currentType != null) {
+ JMethod method = currentType.findMethod(methodName, params);
+ if (method != null) {
+ return method;
+ }
+ currentType = currentType.getSuperclass();
+ }
+
+ JClassType[] interfaces = type.getImplementedInterfaces();
+ for (JClassType iface : interfaces) {
+ JMethod method = iface.findMethod(methodName, params);
+ if (method != null) {
+ return method;
+ }
+ }
+
+ return null;
+ }
}
diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/OnStateChangeVisitor.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/OnStateChangeVisitor.java
new file mode 100644
index 0000000000..ea3e639486
--- /dev/null
+++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/OnStateChangeVisitor.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.server.widgetsetutils.metadata;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JMethod;
+import com.vaadin.client.annotations.OnStateChange;
+import com.vaadin.shared.ui.Connect;
+
+/**
+ * Visits Connector classes and check for methods with @OnStateChange
+ * annotations.
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+public class OnStateChangeVisitor extends TypeVisitor {
+
+ @Override
+ public void visitConnector(TreeLogger logger, JClassType type,
+ ConnectorBundle bundle) throws UnableToCompleteException {
+ Connect connectAnnotation = type.getAnnotation(Connect.class);
+ if (connectAnnotation != null) {
+ // Find all the annotated methods in all the superclasses
+ JClassType connector = type;
+ while (connector != null) {
+ for (JMethod method : connector.getMethods()) {
+ if (method.getAnnotation(OnStateChange.class) != null) {
+ bundle.setNeedsInvoker(connector, method);
+ bundle.setNeedsOnStateChangeHandler(type, method);
+ }
+ }
+
+ connector = connector.getSuperclass();
+ }
+ }
+ }
+
+}
diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/StateInitVisitor.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/StateInitVisitor.java
index 56a404fbb5..f58d1c5d40 100644
--- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/StateInitVisitor.java
+++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/StateInitVisitor.java
@@ -24,7 +24,8 @@ public class StateInitVisitor extends TypeVisitor {
@Override
public void visitConnector(TreeLogger logger, JClassType type,
ConnectorBundle bundle) {
- JMethod getState = findInheritedMethod(type, "getState");
+ JMethod getState = ConnectorBundle
+ .findInheritedMethod(type, "getState");
bundle.setNeedsReturnType(type, getState);
bundle.setNeedsSerialize(getState.getReturnType());
diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/TypeVisitor.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/TypeVisitor.java
index 0af3c6976d..aae610cdcd 100644
--- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/TypeVisitor.java
+++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/TypeVisitor.java
@@ -18,8 +18,6 @@ package com.vaadin.server.widgetsetutils.metadata;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
-import com.google.gwt.core.ext.typeinfo.JMethod;
-import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
@@ -43,27 +41,4 @@ public abstract class TypeVisitor {
// Default does nothing
}
- protected JMethod findInheritedMethod(JClassType type, String methodName,
- JType... params) {
-
- JClassType currentType = type;
- while (currentType != null) {
- JMethod method = currentType.findMethod(methodName, params);
- if (method != null) {
- return method;
- }
- currentType = currentType.getSuperclass();
- }
-
- JClassType[] interfaces = type.getImplementedInterfaces();
- for (JClassType iface : interfaces) {
- JMethod method = iface.findMethod(methodName, params);
- if (method != null) {
- return method;
- }
- }
-
- return null;
- }
-
}
diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/WidgetInitVisitor.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/WidgetInitVisitor.java
index 4de9d2ae99..bac7f5a0f7 100644
--- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/WidgetInitVisitor.java
+++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/WidgetInitVisitor.java
@@ -32,10 +32,11 @@ public class WidgetInitVisitor extends TypeVisitor {
ConnectorBundle bundle) throws UnableToCompleteException {
if (ConnectorBundle.isConnectedComponentConnector(type)) {
// The class in which createWidget is implemented
- JClassType createWidgetClass = findInheritedMethod(type,
- "createWidget").getEnclosingType();
+ JClassType createWidgetClass = ConnectorBundle.findInheritedMethod(
+ type, "createWidget").getEnclosingType();
- JMethod getWidget = findInheritedMethod(type, "getWidget");
+ JMethod getWidget = ConnectorBundle.findInheritedMethod(type,
+ "getWidget");
JClassType widgetType = getWidget.getReturnType().isClass();
// Needs GWT constructor if createWidget is not overridden
@@ -48,7 +49,8 @@ public class WidgetInitVisitor extends TypeVisitor {
}
// Check state properties for @DelegateToWidget
- JMethod getState = findInheritedMethod(type, "getState");
+ JMethod getState = ConnectorBundle.findInheritedMethod(type,
+ "getState");
JClassType stateType = getState.getReturnType().isClass();
Collection<Property> properties = bundle.getProperties(stateType);
@@ -63,8 +65,9 @@ public class WidgetInitVisitor extends TypeVisitor {
String methodName = DelegateToWidget.Helper
.getDelegateTarget(property.getName(),
delegateToWidget.value());
- JMethod delegatedSetter = findInheritedMethod(widgetType,
- methodName, property.getPropertyType());
+ JMethod delegatedSetter = ConnectorBundle
+ .findInheritedMethod(widgetType, methodName,
+ property.getPropertyType());
if (delegatedSetter == null) {
logger.log(
Type.ERROR,