Change-Id: Ic268bfb5704a5c9113dee80017196c72b5236b93tags/7.0.0.beta6
JClassType connectorType = typeOracle.getType(ServerConnector.class | JClassType connectorType = typeOracle.getType(ServerConnector.class | ||||
.getName()); | .getName()); | ||||
JClassType[] subtypes = connectorType.getSubtypes(); | 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); | LoadStyle loadStyle = getLoadStyle(connectorSubtype); | ||||
if (loadStyle != null) { | if (loadStyle != null) { | ||||
connectorsByLoadStyle.get(loadStyle).add(connectorSubtype); | connectorsByLoadStyle.get(loadStyle).add(connectorSubtype); | ||||
return bundles; | 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) | private Collection<TypeVisitor> getVisitors(TypeOracle oracle) | ||||
throws NotFoundException { | throws NotFoundException { | ||||
List<TypeVisitor> visitors = Arrays.<TypeVisitor> asList( | List<TypeVisitor> visitors = Arrays.<TypeVisitor> asList( |
package com.vaadin.server.widgetsetutils.metadata; | package com.vaadin.server.widgetsetutils.metadata; | ||||
import java.util.Map; | |||||
import com.google.gwt.core.ext.TreeLogger; | import com.google.gwt.core.ext.TreeLogger; | ||||
import com.google.gwt.core.ext.TreeLogger.Type; | import com.google.gwt.core.ext.TreeLogger.Type; | ||||
import com.google.gwt.core.ext.UnableToCompleteException; | import com.google.gwt.core.ext.UnableToCompleteException; | ||||
import com.google.gwt.core.ext.typeinfo.JClassType; | import com.google.gwt.core.ext.typeinfo.JClassType; | ||||
import com.google.gwt.dev.util.collect.HashMap; | |||||
import com.vaadin.shared.ui.Connect; | import com.vaadin.shared.ui.Connect; | ||||
public class ConnectorInitVisitor extends TypeVisitor { | public class ConnectorInitVisitor extends TypeVisitor { | ||||
private Map<String, JClassType> processedConnections = new HashMap<String, JClassType>(); | |||||
@Override | @Override | ||||
public void visitConnector(TreeLogger logger, JClassType type, | public void visitConnector(TreeLogger logger, JClassType type, | ||||
ConnectorBundle bundle) throws UnableToCompleteException { | ConnectorBundle bundle) throws UnableToCompleteException { | ||||
+ bundle.getName().replaceAll("^_*", "") + " bundle"); | + bundle.getName().replaceAll("^_*", "") + " bundle"); | ||||
String identifier = connectAnnotation.value().getCanonicalName(); | 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.setIdentifier(type, identifier); | ||||
bundle.setNeedsGwtConstructor(type); | bundle.setNeedsGwtConstructor(type); | ||||
} | } |
/* | |||||
* 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"); | |||||
} | |||||
} |
/* | |||||
* 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(); | |||||
} | |||||
} |
/* | |||||
* 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"); | |||||
} | |||||
} |
<?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> |
/* | |||||
* 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 { | |||||
} |
/* | |||||
* 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); | |||||
} | |||||
} |