Revision: 6913 Author: [email protected] Date: Mon Nov 16 10:04:26 2009 Log: AttributeParsing was pretty much working by accident, and not at all for the deprecated urn:with mechanism. I'm not 100% certain there weren't non-deprecated paths that were broken too.
Attribute parsing is still too complicated, but it's better tested now and goes through only two bottlenecks. Should be able to reduce that to one when the deprecated code is dumped. Also fixes a stray "null" in the deprecation message for urn:with Reviewed by spoon http://gwt-code-reviews.appspot.com/102818 http://code.google.com/p/google-web-toolkit/source/detail?r=6913 Modified: /trunk/user/src/com/google/gwt/uibinder/attributeparsers/BundleAttributeParsers.java /trunk/user/src/com/google/gwt/uibinder/elementparsers/BeanParser.java /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java /trunk/user/src/com/google/gwt/uibinder/rebind/XMLAttribute.java /trunk/user/src/com/google/gwt/uibinder/rebind/XMLElement.java /trunk/user/test/com/google/gwt/uibinder/elementparsers/ElementParserTester.java /trunk/user/test/com/google/gwt/uibinder/rebind/XMLElementTest.java /trunk/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java /trunk/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java /trunk/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml ======================================= --- /trunk/user/src/com/google/gwt/uibinder/attributeparsers/BundleAttributeParsers.java Fri Nov 6 16:08:46 2009 +++ /trunk/user/src/com/google/gwt/uibinder/attributeparsers/BundleAttributeParsers.java Mon Nov 16 10:04:26 2009 @@ -38,7 +38,6 @@ private static final String BUNDLE_URI_SCHEME = "urn:with:"; private final TypeOracle oracle; - private final String gwtPrefix; private final MortalLogger logger; private final OwnerClass ownerClass; private final String templatePath; @@ -49,11 +48,9 @@ */ private final Map<String, BundleAttributeParser> parsers = new LinkedHashMap<String, BundleAttributeParser>(); - public BundleAttributeParsers(TypeOracle oracle, String gwtPrefix, - MortalLogger logger, OwnerClass ownerClass, String templatePath, - JClassType uiOwnerType) { + public BundleAttributeParsers(TypeOracle oracle, MortalLogger logger, + OwnerClass ownerClass, String templatePath, JClassType uiOwnerType) { this.oracle = oracle; - this.gwtPrefix = gwtPrefix; this.logger = logger; this.ownerClass = ownerClass; this.templatePath = templatePath; @@ -66,12 +63,10 @@ public BundleAttributeParser get(XMLAttribute attribute) throws UnableToCompleteException { - if (attribute.getNamespaceUri() == null) { - return null; - } - String attributePrefixUri = attribute.getNamespaceUri(); - if (!attributePrefixUri.startsWith(BUNDLE_URI_SCHEME)) { + + if ((attributePrefixUri == null) + || !attributePrefixUri.startsWith(BUNDLE_URI_SCHEME)) { return null; } @@ -100,10 +95,9 @@ XMLAttribute attribute) throws UnableToCompleteException { final String templateResourceName = attribute.getName().split(":")[0]; - warn("The %1$s mechanism is deprecated. Instead, declare the following " - + "%2$s:with element as a child of your %2$s:UiBinder element: " - + "<%2$s:with field='%3$s' type='%4$s.%5$s' />", BUNDLE_URI_SCHEME, - gwtPrefix, templateResourceName, bundleClass.getPackage().getName(), + warn("\"%s\" is deprecated by " + + "<ui:with field='%s' type='%s.%s' />", BUNDLE_URI_SCHEME, + templateResourceName, bundleClass.getPackage().getName(), bundleClass.getName()); // Try to find any bundle instance created with UiField. ======================================= --- /trunk/user/src/com/google/gwt/uibinder/elementparsers/BeanParser.java Wed Nov 11 22:08:47 2009 +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/BeanParser.java Mon Nov 16 10:04:26 2009 @@ -116,7 +116,7 @@ String propertyName = attribute.getLocalName(); if (setterValues.keySet().contains(propertyName) || requiredValues.containsKey(propertyName)) { - writer.die("Duplicate attribute name: %s", propertyName); + writer.die("In %s, duplicate attribute name: %s", elem, propertyName); } if (unfilledRequiredParams.keySet().contains(propertyName)) { ======================================= --- /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java Wed Nov 11 22:08:47 2009 +++ /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java Mon Nov 16 10:04:26 2009 @@ -262,8 +262,8 @@ handlerEvaluator = new HandlerEvaluator(ownerClass, logger, oracle); attributeParsers = new AttributeParsers(oracle, fieldManager, logger); - bundleParsers = new BundleAttributeParsers(oracle, gwtPrefix, logger, - getOwnerClass(), templatePath, uiOwnerType); + bundleParsers = new BundleAttributeParsers(oracle, logger, getOwnerClass(), + templatePath, uiOwnerType); } /** ======================================= --- /trunk/user/src/com/google/gwt/uibinder/rebind/XMLAttribute.java Fri Nov 6 16:08:46 2009 +++ /trunk/user/src/com/google/gwt/uibinder/rebind/XMLAttribute.java Mon Nov 16 10:04:26 2009 @@ -67,6 +67,7 @@ @Override public String toString() { - return w3cAttr.getName() + "='" + w3cAttr.getValue() + "'"; + return String.format("<%s:%s ... %s=%s ...>", xmlElem.getPrefix(), + xmlElem.getLocalName(), w3cAttr.getName(), w3cAttr.getValue()); } } ======================================= --- /trunk/user/src/com/google/gwt/uibinder/rebind/XMLElement.java Wed Nov 11 22:08:47 2009 +++ /trunk/user/src/com/google/gwt/uibinder/rebind/XMLElement.java Mon Nov 16 10:04:26 2009 @@ -197,9 +197,8 @@ } /** - * Consumes the given attribute as a literal or field reference. The - * type parameter is required to determine how the value is parsed and - * validated. + * Consumes the given attribute as a literal or field reference. The type + * parameter is required to determine how the value is parsed and validated. * * @param name the attribute's full name (including prefix) * @param types the type(s) this attribute is expected to provide @@ -208,14 +207,12 @@ */ public String consumeAttribute(String name, JType type) throws UnableToCompleteException { - String value = consumeRawAttribute(name); - return getParser(getAttribute(name), type).parse(value); + return consumeAttributeWithDefault(name, "", type); } /** - * Consumes the given attribute as a literal or field reference. The - * type parameter is required to determine how the value is parsed and - * validated. + * Consumes the given attribute as a literal or field reference. The type + * parameter is required to determine how the value is parsed and validated. * * @param name the attribute's full name (including prefix) * @param defaultValue the value to @return if the attribute was unset @@ -230,20 +227,12 @@ } /** - * Like {...@link #consumeAttributeWithDefault(String, String, JType)}, but + * Like {...@link #consumeAttributeWithDefault(String, String, JType)}, but * accomodates more complex type signatures. */ public String consumeAttributeWithDefault(String name, String defaultValue, JType[] types) throws UnableToCompleteException { - String value = consumeRawAttribute(name); - if ("".equals(value)) { - return defaultValue; - } - value = getParser(getAttribute(name), types).parse(value); - if ("".equals(value)) { - return defaultValue; - } - return value; + return consumeAttributeWithDefault(false, name, defaultValue, types); } /** @@ -272,11 +261,8 @@ */ public String consumeBooleanAttribute(String name, boolean defaultValue) throws UnableToCompleteException { - String parsed = consumeAttribute(name, getBooleanType()); - if ("".equals(parsed)) { - return Boolean.toString(defaultValue); - } - return parsed; + return consumeAttributeWithDefault(name, Boolean.toString(defaultValue), + getBooleanType()); } /** @@ -517,7 +503,7 @@ } /** - * Consumes the given required attribute as a literal or field reference. The + * Consumes the given required attribute as a literal or field reference. The * types parameters are required to determine how the value is parsed and * validated. * @@ -529,8 +515,19 @@ */ public String consumeRequiredAttribute(String name, JType... types) throws UnableToCompleteException { + /* + * TODO(rjrjr) We have to get the attribute to + * get the parser, and we must get the attribute before we consume the + * value. This nasty subtlety is all down to BundleParsers, which we'll + * hopefully kill off soon. + */ + XMLAttribute attribute = getAttribute(name); + if (attribute == null) { + failRequired(name); + } + AttributeParser parser = getParser(attribute, types); String value = consumeRequiredRawAttribute(name); - return getParser(getAttribute(name), types).parse(value); + return parser.parse(value); } /** @@ -555,7 +552,7 @@ throws UnableToCompleteException { String value = consumeRawAttribute(name); if ("".equals(value)) { - logger.die("In %s, missing required attribute \"%s\"", this, name); + failRequired(name); } return value; } @@ -747,6 +744,30 @@ public String toString() { return debugString; } + + private String consumeAttributeWithDefault(boolean required, String name, + String defaultValue, JType[] types) throws UnableToCompleteException { + /* + * TODO(rjrjr) The only reason we need the attribute here is for getParser, + * and getParser only needs it for horrible old BundleAttributeParsers. When + * that dies, this gets much simpler. + */ + XMLAttribute attribute = getAttribute(name); + if (attribute == null) { + if (required) { + failRequired(name); + } + return defaultValue; + } + String value = attribute.consumeRawValue(); + if ("".equals(value)) { + if (required) { + failRequired(name); + } + return defaultValue; + } + return getParser(attribute, types).parse(value); + } private Iterable<XMLElement> consumeChildElementsNoEmptyCheck() { try { @@ -757,6 +778,10 @@ throw new RuntimeException("Impossible exception", e); } } + + private void failRequired(String name) throws UnableToCompleteException { + logger.die("In %s, missing required attribute \"%s\"", this, name); + } private JType getBooleanType() { if (booleanType == null) { @@ -804,13 +829,11 @@ @SuppressWarnings("deprecation") private AttributeParser getParser(XMLAttribute xmlAttribute, JType... types) throws UnableToCompleteException { - AttributeParser rtn = null; - if (xmlAttribute != null) { - rtn = bundleParsers.get(xmlAttribute); - } + AttributeParser rtn = bundleParsers.get(xmlAttribute); if (rtn == null) { rtn = attributeParsers.get(types); } + return rtn; } ======================================= --- /trunk/user/test/com/google/gwt/uibinder/elementparsers/ElementParserTester.java Wed Nov 11 22:08:47 2009 +++ /trunk/user/test/com/google/gwt/uibinder/elementparsers/ElementParserTester.java Mon Nov 16 10:04:26 2009 @@ -25,6 +25,7 @@ import com.google.gwt.dev.resource.Resource; import com.google.gwt.dev.util.log.PrintWriterTreeLogger; import com.google.gwt.uibinder.attributeparsers.AttributeParsers; +import com.google.gwt.uibinder.attributeparsers.BundleAttributeParsers; import com.google.gwt.uibinder.rebind.FieldManager; import com.google.gwt.uibinder.rebind.FieldWriter; import com.google.gwt.uibinder.rebind.MockMortalLogger; @@ -87,6 +88,7 @@ final ElementParser parser; + @SuppressWarnings("deprecation") ElementParserTester(String parsedTypeName, ElementParser parser) throws UnableToCompleteException { this.parser = parser; @@ -97,7 +99,8 @@ types = state.getTypeOracle(); elemProvider = new XMLElementProviderImpl(new AttributeParsers(types, null, - logger), null, types, logger); + logger), new BundleAttributeParsers(types, logger, null, templatePath, + null), types, logger); fieldManager = new FieldManager(types, logger); JClassType baseType = types.findType("my.Ui.BaseClass"); ======================================= --- /trunk/user/test/com/google/gwt/uibinder/rebind/XMLElementTest.java Wed Nov 11 22:08:47 2009 +++ /trunk/user/test/com/google/gwt/uibinder/rebind/XMLElementTest.java Mon Nov 16 10:04:26 2009 @@ -22,6 +22,7 @@ import com.google.gwt.dev.javac.CompilationStateBuilder; import com.google.gwt.dev.util.log.PrintWriterTreeLogger; import com.google.gwt.uibinder.attributeparsers.AttributeParsers; +import com.google.gwt.uibinder.attributeparsers.BundleAttributeParsers; import com.google.gwt.uibinder.elementparsers.NullInterpreter; import com.google.gwt.uibinder.test.UiJavaResources; @@ -61,6 +62,7 @@ private MockMortalLogger logger; + @SuppressWarnings("deprecation") @Override public void setUp() throws Exception { super.setUp(); @@ -69,7 +71,8 @@ types = state.getTypeOracle(); logger = new MockMortalLogger(); elemProvider = new XMLElementProviderImpl(new AttributeParsers(types, null, - logger), null, types, logger); + logger), new BundleAttributeParsers(types, logger, null, "templatePath", + null), types, logger); init("<doc><elm attr1=\"attr1Value\" attr2=\"attr2Value\"/></doc>"); } @@ -247,7 +250,7 @@ "otherDefault")); } - public void testConsumeRequired() throws UnableToCompleteException { + public void testConsumeRequiredRaw() throws UnableToCompleteException { assertEquals("attr1Value", elm.consumeRequiredRawAttribute("attr1")); try { elm.consumeRequiredRawAttribute("unsetthing"); @@ -256,6 +259,11 @@ assertNotNull(logger.died); } } + + public void testConsumeRequired() throws UnableToCompleteException { + assertEquals("\"attr1Value\"", elm.consumeRequiredAttribute("attr1", + types.findType("java.lang.String"))); + } public void testConsumeRequiredDouble() throws UnableToCompleteException, SAXException, IOException { ======================================= --- /trunk/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java Wed Nov 11 22:08:47 2009 +++ /trunk/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java Mon Nov 16 10:04:26 2009 @@ -137,6 +137,21 @@ foo.setPojo(pojo); assertEquals(foo.getText(), widgetUi.theFoo.getText()); } + + public void testBundleLegacyBeansText() { + assertEquals(widgetUi.legacyValuesForBeans.helloText(), + widgetUi.bundledLabelLegacy.getText()); + } + + public void testBundleLegacyBeansOther() { + assertEquals(widgetUi.legacyValuesForBeans.helloText(), + widgetUi.bundledLabelLegacy.getStyleName()); + } + + public void testBundleLegacyHtml() { + assertEquals(widgetUi.legacyValuesForHtml.helloText(), + widgetUi.bundledDivLegacy.getClassName()); + } public void testCenter() { // TODO(rjrjr) More of a test of HTMLPanelParser ======================================= --- /trunk/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java Wed Nov 11 22:08:47 2009 +++ /trunk/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java Mon Nov 16 10:04:26 2009 @@ -62,8 +62,13 @@ interface Binder extends UiBinder<Widget, WidgetBasedUi> { } - private static final Binder binder = GWT.create(Binder.class); - + static class FakeBundle2 extends FakeBundle { + } + + static class FakeBundle3 extends FakeBundle { + } + private static final Binder binder = GWT.create(Binder.class); + @UiField(provided = true) final WidgetBasedUiExternalResources external = GWT.create(WidgetBasedUiExternalResources.class); @@ -137,6 +142,12 @@ @UiField FooLabel objectBooleanIntoPrimitive; @UiField FooLabel allObjectBoolean; @UiField FooLabel allPrimitiveBoolean; + @UiField(provided = true) + FakeBundle2 legacyValuesForBeans = new FakeBundle2(); + @UiField(provided = true) + FakeBundle3 legacyValuesForHtml = new FakeBundle3(); + @UiField Label bundledLabelLegacy; + @UiField DivElement bundledDivLegacy; public WidgetBasedUi() { external.style().ensureInjected(); ======================================= --- /trunk/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml Wed Nov 11 22:08:47 2009 +++ /trunk/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml Mon Nov 16 10:04:26 2009 @@ -49,6 +49,9 @@ <ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:gwt='urn:import:com.google.gwt.user.client.ui' xmlns:demo='urn:import:com.google.gwt.uibinder.test.client' + + xmlns:legacyValuesForBeans='urn:with:com.google.gwt.uibinder.test.client.WidgetBasedUi.FakeBundle2' + xmlns:legacyValuesForHtml='urn:with:com.google.gwt.uibinder.test.client.WidgetBasedUi.FakeBundle3' ui:defaultLocale="en_US" ui:generateKeys="com.google.gwt.i18n.rebind.keygen.MD5KeyGenerator" @@ -407,6 +410,8 @@ this label gets its text from somplace tricky and its style from a ClientBundle defined outside of this UI:</p> <gwt:Label ui:field='bundledLabel' text="{values.helloText}" styleName="{external.style.prettyText}"/> + <gwt:Label ui:field='bundledLabelLegacy' legacyValuesForBeans:text="helloText" legacyValuesForBeans:styleName="helloText" /> + <div ui:field='bundledDivLegacy' legacyValuesForHtml:class="helloText"/> <!-- Note use of id rather than ui:field, to test that ids work on dom elements --> <p class="{external.style.prettyText}" id='prettyPara'> This stylish paragraph also gets its good looks from the -- http://groups.google.com/group/Google-Web-Toolkit-Contributors
