Author: hlship Date: Thu Apr 29 16:11:06 2010 New Revision: 939357 URL: http://svn.apache.org/viewvc?rev=939357&view=rev Log: TAP5-1120: It is not possible to override the default Translator contributions to the TranslatorSource service
Modified: tapestry/tapestry5/trunk/src/site/apt/upgrade.apt tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServicesMessages.java tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TranslatorSourceImpl.java tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/ServicesStrings.properties tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TranslatorSourceImplTest.java Modified: tapestry/tapestry5/trunk/src/site/apt/upgrade.apt URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/src/site/apt/upgrade.apt?rev=939357&r1=939356&r2=939357&view=diff ============================================================================== --- tapestry/tapestry5/trunk/src/site/apt/upgrade.apt (original) +++ tapestry/tapestry5/trunk/src/site/apt/upgrade.apt Thu Apr 29 16:11:06 2010 @@ -14,6 +14,12 @@ Upgrade Notes Release 5.2.0 +* TranslatorSource + + The configuration type for TranslatorSource has changed in an <<incompatible>> way: from + an unordered collection to a mapped collection; this is to support overrides. This will break + existing module classes that contribute to the TranslatorSource service configuration. + * Assets There have been some changes to how assets operate in Tapestry 5.2. @@ -52,8 +58,8 @@ Release 5.2.0 * Template Parser back to SAX - Tapestry no longer uses a StAX parser (it uses a normal SAX parser) to parse component templates. This change - reduces the number of dependencies for Tapestry, and is a stepping stone to compatibility with + Tapestry no longer uses a StAX parser to parse component templates, it has reverted to using a normal SAX parser. This change + reduces the number of dependencies for Tapestry, and is a stepping stone towards compatibility with Google App Engine. Release 5.1.0.4 Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServicesMessages.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServicesMessages.java?rev=939357&r1=939356&r2=939357&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServicesMessages.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServicesMessages.java Thu Apr 29 16:11:06 2010 @@ -153,11 +153,6 @@ public class ServicesMessages return MESSAGES.format("unknown-validator-type", validatorType, InternalUtils.join(knownValidatorTypes)); } - public static String unknownTranslatorType(String translatorType, List<String> knownTranslatorTypes) - { - return MESSAGES.format("unknown-translator-type", translatorType, InternalUtils.join(knownTranslatorTypes)); - } - public static String validatorSpecificationParseError(int cursor, String specification) { return MESSAGES.format("validator-specification-parse-error", specification.charAt(cursor), cursor + 1, Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TranslatorSourceImpl.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TranslatorSourceImpl.java?rev=939357&r1=939356&r2=939357&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TranslatorSourceImpl.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TranslatorSourceImpl.java Thu Apr 29 16:11:06 2010 @@ -1,10 +1,10 @@ -// Copyright 2007, 2008 The Apache Software Foundation +// Copyright 2007, 2008, 2010 The Apache Software Foundation // // 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 +// 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, @@ -14,34 +14,41 @@ package org.apache.tapestry5.internal.services; +import java.util.List; +import java.util.Map; + import org.apache.tapestry5.Translator; import org.apache.tapestry5.ioc.internal.util.CollectionFactory; -import org.apache.tapestry5.ioc.internal.util.InternalUtils; +import org.apache.tapestry5.ioc.util.AvailableValues; import org.apache.tapestry5.ioc.util.StrategyRegistry; +import org.apache.tapestry5.ioc.util.UnknownValueException; import org.apache.tapestry5.services.InvalidationListener; import org.apache.tapestry5.services.TranslatorSource; -import java.util.Collection; -import java.util.List; -import java.util.Map; - public class TranslatorSourceImpl implements TranslatorSource, InvalidationListener { private final Map<String, Translator> translators = CollectionFactory.newCaseInsensitiveMap(); private final StrategyRegistry<Translator> registry; - public TranslatorSourceImpl(Collection<Translator> configuration) + public TranslatorSourceImpl(Map<Class, Translator> configuration) { - Map<Class, Translator> typeToTranslator = CollectionFactory.newMap(); - - for (Translator t : configuration) + for (Map.Entry<Class, Translator> me : configuration.entrySet()) { - translators.put(t.getName(), t); - typeToTranslator.put(t.getType(), t); + Class type = me.getKey(); + Translator translator = me.getValue(); + + if (!type.equals(translator.getType())) + throw new RuntimeException( + String + .format( + "Contributed translator for type %s reports its type as %s. Please change the contribution so that the key matches that translator type.", + type.getName(), translator.getType().getName())); + + translators.put(translator.getName(), translator); } - registry = StrategyRegistry.newInstance(Translator.class, typeToTranslator, true); + registry = StrategyRegistry.newInstance(Translator.class, configuration, true); } public Translator get(String name) @@ -50,8 +57,8 @@ public class TranslatorSourceImpl implem Translator result = translators.get(name); if (result == null) - throw new RuntimeException(ServicesMessages.unknownTranslatorType(name, InternalUtils - .sortedKeys(translators))); + throw new UnknownValueException(String.format("Unknown translator type '%s'.", name), new AvailableValues( + "translators", translators)); return result; } Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java?rev=939357&r1=939356&r2=939357&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java Thu Apr 29 16:11:06 2010 @@ -1008,11 +1008,11 @@ public final class TapestryModule * <li>BigDecimal</li> * </ul> */ - public static void contributeTranslatorSource(Configuration<Translator> configuration, + public static void contributeTranslatorSource(MappedConfiguration<Class, Translator> configuration, NumericTranslatorSupport support) { - configuration.add(new StringTranslator()); + configuration.add(String.class, new StringTranslator()); Class[] types = new Class[] { Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, BigInteger.class, @@ -1022,7 +1022,7 @@ public final class TapestryModule { String name = type.getSimpleName().toLowerCase(); - configuration.add(new NumericTranslator(name, type, support)); + configuration.add(type, new NumericTranslator(name, type, support)); } } Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/ServicesStrings.properties URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/ServicesStrings.properties?rev=939357&r1=939356&r2=939357&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/ServicesStrings.properties (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/ServicesStrings.properties Thu Apr 29 16:11:06 2010 @@ -41,7 +41,6 @@ asset-does-not-exist=Unable to locate as wrong-asset-digest=The asset digest in the request does not match the actual digest for asset '%s'. This indicates that the content of the asset has changed between requests. unknown-validator-type=Unknown validator type '%s'. Configured validators are %s. validator-specification-parse-error=Unexpected character '%s' at position %d of input string: %s -unknown-translator-type=Unknown translator type '%s'. Configured translators are %s. missing-from-environment=No object of type %s is available from the Environment. Available types are %s. invalid-component-event-result=A component event handler method returned the value %s. Return type %s can not be handled. Configured return types are %s. undefined-tapestry-attribute=Element <%s> does not support an attribute named '%s'. The only allowed attribute name is '%s'. Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TranslatorSourceImplTest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TranslatorSourceImplTest.java?rev=939357&r1=939356&r2=939357&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TranslatorSourceImplTest.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TranslatorSourceImplTest.java Thu Apr 29 16:11:06 2010 @@ -1,10 +1,10 @@ -// Copyright 2007, 2008, 2009 The Apache Software Foundation +// Copyright 2007, 2008, 2009, 2010 The Apache Software Foundation // // 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 +// 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, @@ -14,6 +14,13 @@ package org.apache.tapestry5.internal.services; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.text.DecimalFormatSymbols; +import java.text.ParseException; +import java.util.Locale; +import java.util.Map; + import org.apache.tapestry5.Field; import org.apache.tapestry5.Translator; import org.apache.tapestry5.ValidationException; @@ -22,19 +29,13 @@ import org.apache.tapestry5.internal.tra import org.apache.tapestry5.internal.translator.BigIntegerNumericFormatter; import org.apache.tapestry5.ioc.internal.util.CollectionFactory; import org.apache.tapestry5.ioc.services.ThreadLocale; +import org.apache.tapestry5.ioc.util.UnknownValueException; import org.apache.tapestry5.services.TranslatorSource; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.text.DecimalFormatSymbols; -import java.text.ParseException; -import java.util.Collection; -import java.util.Locale; - public class TranslatorSourceImplTest extends InternalBaseTestCase { private TranslatorSource source; @@ -44,37 +45,68 @@ public class TranslatorSourceImplTest ex { source = getService(TranslatorSource.class); } - + @BeforeMethod public void setupThreadLocale() { getService(ThreadLocale.class).setLocale(Locale.ENGLISH); } - @Test public void found_translator_by_name() { Translator translator = mockTranslator("mock", String.class); - Collection<Translator> configuration = CollectionFactory.newList(translator); - replay(); - TranslatorSource source = new TranslatorSourceImpl(configuration); + TranslatorSource source = new TranslatorSourceImpl(newConfiguration(String.class, translator)); assertSame(source.get("mock"), translator); verify(); } + private Map<Class, Translator> newConfiguration(Class type, Translator t) + { + Map<Class, Translator> result = CollectionFactory.newMap(); + result.put(type, t); + + return result; + } + + @Test + public void key_and_type_mismatch() + { + Translator t = mockTranslator(); + + train_getType(t, Long.class); + + replay(); + + try + { + new TranslatorSourceImpl(newConfiguration(Integer.class, t)); + unreachable(); + } + catch (RuntimeException ex) + { + assertMessageContains(ex, + "Contributed translator for type java.lang.Integer reports its type as java.lang.Long."); + } + + verify(); + } + @Test public void unknown_translator_is_failure() { Translator fred = mockTranslator("fred", String.class); Translator barney = mockTranslator("barney", Long.class); - Collection<Translator> configuration = CollectionFactory.newList(fred, barney); + Map<Class, Translator> configuration = CollectionFactory.newMap(); + + configuration.put(String.class, fred); + configuration.put(Long.class, barney); replay(); @@ -85,19 +117,17 @@ public class TranslatorSourceImplTest ex source.get("wilma"); unreachable(); } - catch (RuntimeException ex) + catch (UnknownValueException ex) { - assertEquals( - ex.getMessage(), - "Unknown translator type 'wilma'. Configured translators are barney, fred."); + assertMessageContains(ex, "Unknown translator type 'wilma'."); } } - @DataProvider public Object[][] to_client_data() { - return new Object[][] { + return new Object[][] + { { Byte.class, (byte) 65, "65" }, @@ -105,7 +135,7 @@ public class TranslatorSourceImplTest ex { Long.class, 12345l, "12345" }, - // Is this a bug? We seem to be using a JDK- or locale-defined level of precision. + // Is this a bug? We seem to be using a JDK- or locale-defined level of precision. // Maybe translators need room for configuration just like validators, so that // the correct decimal format string could be specified in the message catalog. @@ -117,12 +147,10 @@ public class TranslatorSourceImplTest ex { Float.class, (float) -22.7, "-22.7" }, - { BigInteger.class, new BigInteger("123456789012345678901234567890"), - "123456789012345678901234567890" }, + { BigInteger.class, new BigInteger("123456789012345678901234567890"), "123456789012345678901234567890" }, { BigDecimal.class, new BigDecimal("-9876543219876543321987654321.12345123451234512345"), - "-9876543219876543321987654321.12345123451234512345" } - }; + "-9876543219876543321987654321.12345123451234512345" } }; } @Test(dataProvider = "to_client_data") @@ -138,7 +166,8 @@ public class TranslatorSourceImplTest ex @DataProvider public Object[][] parse_client_success_data() { - return new Object[][] { + return new Object[][] + { { Byte.class, " 23 ", (byte) 23 }, @@ -160,8 +189,7 @@ public class TranslatorSourceImplTest ex new BigInteger("-123456789012345678901234567890") }, { BigDecimal.class, "-9,876,543,219,876,543,321,987,654,321.12345123451234512345", - new BigDecimal("-9876543219876543321987654321.12345123451234512345") } - }; + new BigDecimal("-9876543219876543321987654321.12345123451234512345") } }; } @Test(dataProvider = "parse_client_success_data") @@ -180,20 +208,20 @@ public class TranslatorSourceImplTest ex String intError = "You must provide an integer value for Fred."; String floatError = "You must provide a numeric value for Fred."; - return new Object[][] { + return new Object[][] + { - { Byte.class, "fred", intError }, + { Byte.class, "fred", intError }, - { Integer.class, "fred", intError }, + { Integer.class, "fred", intError }, - { Long.class, "fred", intError }, + { Long.class, "fred", intError }, - { Double.class, "fred", floatError }, + { Double.class, "fred", floatError }, - { Float.class, "fred", floatError }, + { Float.class, "fred", floatError }, - { Short.class, "fred", intError } - }; + { Short.class, "fred", intError } }; } @Test(dataProvider = "parse_client_failure_data") @@ -221,11 +249,10 @@ public class TranslatorSourceImplTest ex public void find_by_type() { Translator t = mockTranslator("string", String.class); - Collection<Translator> configuration = CollectionFactory.newList(t); replay(); - TranslatorSource source = new TranslatorSourceImpl(configuration); + TranslatorSource source = new TranslatorSourceImpl(newConfiguration(String.class, t)); assertSame(source.getByType(String.class), t); assertSame(source.findByType(String.class), t); @@ -240,7 +267,9 @@ public class TranslatorSourceImplTest ex Translator string = mockTranslator("string", String.class); Translator bool = mockTranslator("bool", Boolean.class); - Collection<Translator> configuration = CollectionFactory.newList(string, bool); + Map<Class, Translator> configuration = CollectionFactory.newMap(); + configuration.put(String.class, string); + configuration.put(Boolean.class, bool); replay(); @@ -254,7 +283,7 @@ public class TranslatorSourceImplTest ex catch (IllegalArgumentException ex) { assertEquals(ex.getMessage(), - "No translator is defined for type java.lang.Integer. Registered types: java.lang.Boolean, java.lang.String."); + "No translator is defined for type java.lang.Integer. Registered types: java.lang.Boolean, java.lang.String."); } verify(); @@ -293,5 +322,4 @@ public class TranslatorSourceImplTest ex assertEquals(f.toClient(big), "*123456#797956563434"); } - }