Change-Id: Ic268bfb5704a5c9113dee80017196c72b5236b93tags/7.0.0.beta6
@@ -583,10 +583,12 @@ public class ConnectorBundleLoaderFactory extends Generator { | |||
JClassType connectorType = typeOracle.getType(ServerConnector.class | |||
.getName()); | |||
JClassType[] subtypes = connectorType.getSubtypes(); | |||
for (JClassType connectorSubtype : subtypes) { | |||
if (!connectorSubtype.isAnnotationPresent(Connect.class)) { | |||
continue; | |||
} | |||
// Find all types with a valid mapping | |||
Collection<JClassType> selectedTypes = getMappedTypes(logger, subtypes); | |||
// Group by load style | |||
for (JClassType connectorSubtype : selectedTypes) { | |||
LoadStyle loadStyle = getLoadStyle(connectorSubtype); | |||
if (loadStyle != null) { | |||
connectorsByLoadStyle.get(loadStyle).add(connectorSubtype); | |||
@@ -637,6 +639,79 @@ public class ConnectorBundleLoaderFactory extends Generator { | |||
return bundles; | |||
} | |||
private Collection<JClassType> getMappedTypes(TreeLogger logger, | |||
JClassType[] types) throws UnableToCompleteException { | |||
Map<String, JClassType> mappings = new HashMap<String, JClassType>(); | |||
// Keep track of what has happened to avoid logging intermediate state | |||
Map<JClassType, List<JClassType>> replaced = new HashMap<JClassType, List<JClassType>>(); | |||
for (JClassType type : types) { | |||
Connect connectAnnotation = type.getAnnotation(Connect.class); | |||
if (connectAnnotation == null) { | |||
continue; | |||
} | |||
String identifier = connectAnnotation.value().getCanonicalName(); | |||
JClassType previousMapping = mappings.put(identifier, type); | |||
if (previousMapping != null) { | |||
// There are multiple mappings, pick the subclass | |||
JClassType subclass; | |||
JClassType superclass; | |||
if (previousMapping.isAssignableFrom(type)) { | |||
subclass = type; | |||
superclass = previousMapping; | |||
} else if (type.isAssignableFrom(previousMapping)) { | |||
subclass = previousMapping; | |||
superclass = type; | |||
} else { | |||
// Neither inherits from the other - this is a conflict | |||
logger.log( | |||
Type.ERROR, | |||
"Conflicting @Connect mappings detected for " | |||
+ identifier | |||
+ ": " | |||
+ type.getQualifiedSourceName() | |||
+ " and " | |||
+ previousMapping.getQualifiedSourceName() | |||
+ ". There can only be multiple @Connect mappings for the same server-side type if one is the subclass of the other."); | |||
throw new UnableToCompleteException(); | |||
} | |||
mappings.put(identifier, subclass); | |||
// Inherit any previous replacements | |||
List<JClassType> previousReplacements = replaced | |||
.remove(superclass); | |||
if (previousReplacements == null) { | |||
previousReplacements = new ArrayList<JClassType>(); | |||
} | |||
previousReplacements.add(superclass); | |||
replaced.put(subclass, previousReplacements); | |||
} | |||
} | |||
// Log the final set of replacements | |||
for (Entry<JClassType, List<JClassType>> entry : replaced.entrySet()) { | |||
String msg = entry.getKey().getQualifiedSourceName() + " replaces "; | |||
List<JClassType> list = entry.getValue(); | |||
for (int i = 0; i < list.size(); i++) { | |||
if (i != 0) { | |||
msg += ", "; | |||
} | |||
msg += list.get(i).getQualifiedSourceName(); | |||
} | |||
logger.log(Type.INFO, msg); | |||
} | |||
// Return the types of the final mapping | |||
return mappings.values(); | |||
} | |||
private Collection<TypeVisitor> getVisitors(TypeOracle oracle) | |||
throws NotFoundException { | |||
List<TypeVisitor> visitors = Arrays.<TypeVisitor> asList( |
@@ -4,19 +4,14 @@ | |||
package com.vaadin.server.widgetsetutils.metadata; | |||
import java.util.Map; | |||
import com.google.gwt.core.ext.TreeLogger; | |||
import com.google.gwt.core.ext.TreeLogger.Type; | |||
import com.google.gwt.core.ext.UnableToCompleteException; | |||
import com.google.gwt.core.ext.typeinfo.JClassType; | |||
import com.google.gwt.dev.util.collect.HashMap; | |||
import com.vaadin.shared.ui.Connect; | |||
public class ConnectorInitVisitor extends TypeVisitor { | |||
private Map<String, JClassType> processedConnections = new HashMap<String, JClassType>(); | |||
@Override | |||
public void visitConnector(TreeLogger logger, JClassType type, | |||
ConnectorBundle bundle) throws UnableToCompleteException { | |||
@@ -26,18 +21,6 @@ public class ConnectorInitVisitor extends TypeVisitor { | |||
+ bundle.getName().replaceAll("^_*", "") + " bundle"); | |||
String identifier = connectAnnotation.value().getCanonicalName(); | |||
JClassType previousMapping = processedConnections.put(identifier, | |||
type); | |||
if (previousMapping != null) { | |||
logger.log( | |||
Type.ERROR, | |||
"Multiple @Connect mappings detected for " + identifier | |||
+ ": " + type.getQualifiedSourceName() | |||
+ " and " | |||
+ previousMapping.getQualifiedSourceName()); | |||
throw new UnableToCompleteException(); | |||
} | |||
bundle.setIdentifier(type, identifier); | |||
bundle.setNeedsGwtConstructor(type); | |||
} |
@@ -0,0 +1,31 @@ | |||
/* | |||
* Copyright 2012 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.tests.widgetset.client; | |||
import com.vaadin.shared.ui.Connect; | |||
import com.vaadin.tests.widgetset.server.ReplaceComponent; | |||
@Connect(value = ReplaceComponent.class) | |||
public class IntermediateReplaceConnector extends ReplacedConnector { | |||
@Override | |||
protected void init() { | |||
super.init(); | |||
getWidget().setHTML( | |||
IntermediateReplaceConnector.class.getName() | |||
+ ", should not be used"); | |||
} | |||
} |
@@ -0,0 +1,37 @@ | |||
/* | |||
* Copyright 2012 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.tests.widgetset.client; | |||
import com.google.gwt.user.client.ui.HTML; | |||
import com.vaadin.client.ui.AbstractComponentConnector; | |||
import com.vaadin.shared.ui.Connect; | |||
import com.vaadin.tests.widgetset.server.ReplaceComponent; | |||
@Connect(ReplaceComponent.class) | |||
public class ReplacedConnector extends AbstractComponentConnector { | |||
@Override | |||
protected void init() { | |||
getWidget().setHTML( | |||
ReplacedConnector.class.getName() + ", should not be used"); | |||
} | |||
@Override | |||
public HTML getWidget() { | |||
return (HTML) super.getWidget(); | |||
} | |||
} |
@@ -0,0 +1,30 @@ | |||
/* | |||
* Copyright 2012 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.tests.widgetset.client; | |||
import com.vaadin.shared.ui.Connect; | |||
import com.vaadin.tests.widgetset.server.ReplaceComponent; | |||
@Connect(value = ReplaceComponent.class) | |||
public class ReplacingConnector extends IntermediateReplaceConnector { | |||
@Override | |||
protected void init() { | |||
super.init(); | |||
getWidget().setHTML( | |||
ReplacingConnector.class.getName() + ", this is the right one"); | |||
} | |||
} |
@@ -0,0 +1,26 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | |||
<link rel="selenium.base" href="" /> | |||
<title>New Test</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<thead> | |||
<tr><td rowspan="1" colspan="3">New Test</td></tr> | |||
</thead><tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/run/com.vaadin.tests.widgetset.server.ReplaceComponentUI?restartApplication</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertText</td> | |||
<td>vaadin=runcomvaadintestswidgetsetserverReplaceComponentUI::/VVerticalLayout[0]/VOrderedLayout$Slot[1]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/HTML[0]</td> | |||
<td>com.vaadin.tests.widgetset.client.ReplacingConnector, this is the right one</td> | |||
</tr> | |||
</tbody></table> | |||
</body> | |||
</html> |
@@ -0,0 +1,23 @@ | |||
/* | |||
* Copyright 2012 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.tests.widgetset.server; | |||
import com.vaadin.ui.AbstractComponent; | |||
public class ReplaceComponent extends AbstractComponent { | |||
} |
@@ -0,0 +1,42 @@ | |||
/* | |||
* Copyright 2012 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.tests.widgetset.server; | |||
import com.vaadin.annotations.Widgetset; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.tests.components.AbstractTestUI; | |||
import com.vaadin.tests.widgetset.TestingWidgetSet; | |||
@Widgetset(TestingWidgetSet.NAME) | |||
public class ReplaceComponentUI extends AbstractTestUI { | |||
@Override | |||
protected void setup(VaadinRequest request) { | |||
addComponent(new ReplaceComponent()); | |||
} | |||
@Override | |||
protected String getTestDescription() { | |||
return "Tests that the right client-side connector is used when there are multiple connectors with @Connect mappings to the same server-side component."; | |||
} | |||
@Override | |||
protected Integer getTicketNumber() { | |||
return Integer.valueOf(9826); | |||
} | |||
} |