You can subscribe to this list here.
2004 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(4) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2005 |
Jan
(3) |
Feb
(4) |
Mar
(1) |
Apr
(5) |
May
|
Jun
(3) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(2) |
Dec
(6) |
2006 |
Jan
(1) |
Feb
(6) |
Mar
(9) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(12) |
2007 |
Jan
(44) |
Feb
(36) |
Mar
(24) |
Apr
(59) |
May
(6) |
Jun
|
Jul
|
Aug
|
Sep
(3) |
Oct
(2) |
Nov
(4) |
Dec
(3) |
2008 |
Jan
(34) |
Feb
(4) |
Mar
|
Apr
|
May
|
Jun
(4) |
Jul
|
Aug
(7) |
Sep
(2) |
Oct
|
Nov
(3) |
Dec
|
2009 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(5) |
Nov
|
Dec
|
2010 |
Jan
|
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Matt S. <mat...@sp...> - 2008-01-07 16:58:28
|
Sorry about that! I renamed the method isCommonsCollections3Present because the class referenced is new in 3.x (I meant to do this before, but I forgot). Matt S On Jan 7, 2008 11:32 AM, Matt Benson <gud...@ya...> wrote: > > --- Matt Sgarlata <mat...@sp...> > wrote: > > > I have been thinking more about this approach, and > > it's really starting to > > grow on me. I do have one concern though, can this > > approach be extended to > > Copiers? For example, a Map -> Object copy could > > probably be considered an > > imprecise transformation because the Map may have > > more keys than the Object > > has properties. > > > > In addition to your approach, I also like the idea > > of cleaning up the > > internal implementation in Morph so that ordering of > > source and destination > > classes is preserved for the following reasons: > > 1) for at least some portion of users, setting the > > order of source and > > destination classes will make sense as an indication > > of the transformer's > > preferences for performing transformations (so for > > this class of users, > > creating new transformers that play nicely with the > > ChainedTransformerTestCase will be simpler) > > 2) I think a general change from using HashSets to > > ordered sets in Morph's > > implementation will mean transformations happen more > > consistently across > > JVMs and across time on the same JVM, leading to a > > more stable platform > > > > So, what I did is I basically went through the Morph > > codebase and replaced > > HashSets with ordered sets (preference order is: JDK > > 1.4 LinkedHashSet, > > Commons-collections ListOrderedSet, copy of > > ListOrderedSet in > > net.sf.morph.util). I was never able to modify the > > ChainedTransformerTestCase so that it consistently > > threw an error. However, > > after working on the test case long enough, > > eventually something changed in > > my environment so that the test started to fail. I > > did my change of > > HashSets to ordered sets, and that was able to fix > > the broken test. > > I seem to be missing a > ClassUtils.isCommonsCollectionsPresent() method after > syncing. I'll create my own for now, but it does seem > to be missing. Thanks! > > -Matt B > > > > > I checked in my changes for you to take a look at... > > > > Matt S > > > > On Jan 6, 2008 12:59 PM, Matt Benson > > <gud...@ya...> wrote: > > > > > Here's what I've got. > > > > > > -Matt B > > > > > > > > > > > > > > > > ____________________________________________________________________________________ > > > Be a better friend, newshound, and > > > know-it-all with Yahoo! Mobile. Try it now. > > > > > > http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ > > > > > > Index: > > > > > > > src/core/net/sf/morph/transform/transformers/SimpleDelegatingTransformer.java > > > > > > =================================================================== > > > --- > > > > > > > src/core/net/sf/morph/transform/transformers/SimpleDelegatingTransformer.java > > > (revision 357) > > > +++ > > > > > > > src/core/net/sf/morph/transform/transformers/SimpleDelegatingTransformer.java > > > (working copy) > > > @@ -1,5 +1,5 @@ > > > /* > > > - * Copyright 2004-2005, 2007 the original author > > or authors. > > > + * Copyright 2004-2005, 2007-2008 the original > > author or authors. > > > * > > > * 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 > > > @@ -35,6 +35,7 @@ > > > import net.sf.morph.transform.DecoratedConverter; > > > import net.sf.morph.transform.DecoratedCopier; > > > import > > net.sf.morph.transform.ExplicitTransformer; > > > +import net.sf.morph.transform.ImpreciseConverter; > > > import net.sf.morph.transform.NodeCopier; > > > import > > net.sf.morph.transform.TransformationException; > > > import net.sf.morph.transform.Transformer; > > > @@ -93,11 +94,11 @@ > > > * @since Dec 12, 2004 > > > */ > > > public class SimpleDelegatingTransformer extends > > BaseCompositeTransformer > > > implements > > > - SpecializableComposite, > > ExplicitTransformer, Transformer, > > > DecoratedCopier, DecoratedConverter, Cloneable { > > > + SpecializableComposite, > > ExplicitTransformer, Transformer, > > > DecoratedCopier, > > > + DecoratedConverter, Cloneable, > > ImpreciseConverter { > > > > > > //TODO extract BaseDelegatingTransformer > > with pluggable delegate > > > selection > > > > > > - > > > private static class MapThreadLocal extends > > ThreadLocal { > > > protected Object initialValue() { > > > return new HashMap(); > > > @@ -138,6 +139,7 @@ > > > } > > > > > > private Specializer specializer; > > > + private boolean preferPreciseTransformers; > > > > > > private transient ThreadLocal > > > visitedSourceToDestinationMapThreadLocal = new > > MapThreadLocal(); > > > private transient ThreadLocal > > stackDepthThreadLocal = new > > > StackDepthThreadLocal(); > > > @@ -225,6 +227,14 @@ > > > > > > /** > > > * {@inheritDoc} > > > + */ > > > + protected boolean > > isImpreciseConversionImpl(Class > > > destinationClass, Class sourceClass) { > > > + return > > TransformerUtils.isImpreciseConversion > > > (getTransformer(destinationClass, > > > + sourceClass), > > destinationClass, > > > sourceClass); > > > + } > > > + > > > + /** > > > + * {@inheritDoc} > > > * @see > > > > > > net.sf.morph.transform.transformers.BaseTransformer#getSourceClassesImpl() > > > */ > > > protected Class[] getSourceClassesImpl() > > throws Exception { > > > @@ -477,6 +487,7 @@ > > > * if no suitable transformer > > could be found > > > */ > > > private Transformer getTransformer(Class > > transformerType, Class > > > destinationClass, Class sourceClass) throws > > TransformationException { > > > + Transformer candidate = null; > > > for (int i = 0; i < > > components.length; i++) { > > > // if the transformer is > > the correct type > > > Transformer transformer = > > (Transformer) > > > components[i]; > > > @@ -484,6 +495,13 @@ > > > // if the > > transformer is capable of > > > performing the transformation > > > if > > (TransformerUtils.isTransformable( > > > > > transformer, > > > destinationClass, sourceClass)) { > > > + if > > (isPreferPreciseTransformers() > > > + > > && candidate == > > > null > > > + > > && > > > > > TransformerUtils.isImpreciseConversion(transformer, > > > + > > > destinationClass, sourceClass)) { > > > + > > candidate = transformer; > > > + > > continue; > > > + } > > > if > > (getLog().isTraceEnabled()) { > > > > > getLog().trace("Using " > > > > > + > > > > > ClassUtils.getUnqualifiedClassName(transformerType) > > > @@ -496,7 +514,9 @@ > > > return > > transformer; > > > } > > > } > > > - > > > + if (candidate != null) { > > > + return candidate; > > > + } > > > } > > > throw new TransformationException( > > > "Could not find a > > transformer that can transform > > > objects of " > > > @@ -612,4 +632,20 @@ > > > source); > > > } > > > > > > + /** > > > + * Get the preferPreciseTransformers. > > > + * @return boolean > > > + */ > > > + public boolean > > isPreferPreciseTransformers() { > > > + return preferPreciseTransformers; > > > + } > > > + > > > + /** > > > + * Set the preferPreciseTransformers. > > Default false. > > > + * @param preferPreciseTransformers the > > boolean to set > > > + */ > > > + public void > > setPreferPreciseTransformers(boolean > > > preferPreciseTransformers) { > > > + this.preferPreciseTransformers = > > > preferPreciseTransformers; > > > + } > > > + > > > } > > > \ No newline at end of file > > > Index: > > > src/core/net/sf/morph/transform/transformers/BaseTransformer.java > > > > > > =================================================================== > > > --- > > > src/core/net/sf/morph/transform/transformers/BaseTransformer.java > > > (revision 358) > > > +++ > > > src/core/net/sf/morph/transform/transformers/BaseTransformer.java > > > (working copy) > > > @@ -570,6 +570,35 @@ > > > } > > > } > > > > > > + /** > > > + * Implementation of isImpreciseConversion > > > + * @param destinationClass > > > + * @param sourceClass > > > + * @return > > > + */ > > > + protected boolean > > isImpreciseConversionImpl(Class > > > destinationClass, Class sourceClass) { > > > + return destinationClass == null && > > sourceClass != null; > > > + } > > > + > > > + /** > > > + * Learn whether the specified conversion > > yields an imprecise > > > result. > > > + * @param destinationClass > > > + * @param sourceClass > > > + * @return boolean > > > + */ > > > + public final boolean > > isImpreciseConversion(Class destinationClass, > > > Class sourceClass) { > > > + try { > > > + return > > isImpreciseConversionImpl(destinationClass, > > > sourceClass); > > > + } catch (Exception e) { > > > + if (e instanceof > > RuntimeException && > > > !isWrappingRuntimeExceptions()) { > > > + throw > > (RuntimeException) e; > > > + } > > > + throw new > > TransformationException("Could not > > > determine if conversion of " > > > + + > > sourceClass + " to " + > > > destinationClass > > > + + " > > results in a loss of > > > precision", e); > > > + } > > > + } > > > + > > > // property getters and setters > > > > > > /** > > > Index: > > > > > > src/core/net/sf/morph/transform/transformers/ChainedTransformer.java > > > > > > =================================================================== > > > --- > > > src/core/net/sf/morph/transform/transformers/ChainedTransformer.java > > > (revision 357) > > > +++ > > > src/core/net/sf/morph/transform/transformers/ChainedTransformer.java > > > (working copy) > > > @@ -1,5 +1,5 @@ > > > /* > > > - * Copyright 2004-2005, 2007 the original author > > or authors. > > > + * Copyright 2004-2005, 2007-2008 the original > > author or authors. > > > * > > > * 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 > > > @@ -16,6 +16,7 @@ > > > package net.sf.morph.transform.transformers; > > > > > > import java.util.ArrayList; > > > +import java.util.Iterator; > > > import java.util.List; > > > import java.util.Locale; > > > > > > @@ -25,6 +26,7 @@ > > > import net.sf.morph.transform.DecoratedConverter; > > > import net.sf.morph.transform.DecoratedCopier; > > > import > > net.sf.morph.transform.ExplicitTransformer; > > > +import net.sf.morph.transform.ImpreciseConverter; > > > import > > net.sf.morph.transform.TransformationException; > > > import net.sf.morph.transform.Transformer; > > > import > > net.sf.morph.transform.copiers.CopierDecorator; > > > @@ -40,7 +42,7 @@ > > > * @since Nov 24, 2004 > > > */ > > > public class ChainedTransformer extends > > BaseCompositeTransformer > > > implements > > > - DecoratedConverter, > > DecoratedCopier, ExplicitTransformer { > > > + DecoratedConverter, > > DecoratedCopier, ExplicitTransformer, > > > ImpreciseConverter { > > > > > > private Converter copyConverter; > > > > > > @@ -67,6 +69,14 @@ > > > } > > > > > > /** > > > + * {@inheritDoc} > > > + */ > > > + protected boolean > > isImpreciseConversionImpl(Class > > > destinationClass, Class sourceClass) { > > > + List conversionPath = > > getConversionPath(destinationClass, > > > sourceClass); > > > + return !isPrecise(conversionPath, > > sourceClass, 0); > > > + } > > > + > > > + /** > > > * Get the converter used when using a > > ChainedTransformer as a > > > Copier. > > > * @return > > > */ > > > @@ -113,6 +123,7 @@ > > > throw new > > TransformationException(destinationClass, > > > sourceType, null, > > > "Chained > > conversion path could not > > > be determined"); > > > } > > > + log.debug("Using chained > > conversion path " + > > > conversionPath); > > > Object o = source; > > > for (int i = 0; i < > > conversionPath.size(); i++) { > > > o = > > getConverter(chain[i]).convert((Class) > > > conversionPath.get(i), o, locale); > > > @@ -144,6 +155,7 @@ > > > throw new > > TransformationException(destinationClass, > > > source, null, > > > "Chained > > conversion path could not > > > be determined"); > > > } > > > + log.debug("Using chained > > conversion path " + > > > conversionPath); > > > Object last = > > getCopyConverter().convert((Class) > > > conversionPath.get(chain.length - 2), source, > > locale); > > > ((Copier) copier).copy(destination, > > last, locale); > > > } > > > @@ -192,13 +204,7 @@ > > > * @return List > > > */ > > > protected List getConversionPath(Class > > destinationType, Class > > > sourceType) { > > > - if (sourceType != null) { > > > - List withoutNull = > > > getConversionPath(destinationType, sourceType, 0, > > false); > > > - if (withoutNull != null) { > > > - return > > withoutNull; > > > - } > > > - } > > > - return > > getConversionPath(destinationType, sourceType, 0, > > > true); > > > + return > > getConversionPath(destinationType, sourceType, 0); > > > } > > > > > > /** > > > @@ -210,7 +216,7 @@ > > > * @param allowNull > > > * @return List > > > */ > > > - private List getConversionPath(Class > > destinationType, Class > > > sourceType, int index, boolean allowNull) { > > > + private List getConversionPath(Class > > destinationType, Class > > > sourceType, int index) { > > > Transformer[] chain = getChain(); > > > Transformer c = chain[index]; > > > if (index + 1 == chain.length) { > > > @@ -221,22 +227,38 @@ > > > } > > > return null; > > > } > > > + List possibleResult = null; > > > Class[] available = > > c.getDestinationClasses(); > > > for (int i = 0; i < > > available.length; i++) { > > > - if (available[i] == null > > && !allowNull) { > > > - continue; > > > - } > > > if > > (TransformerUtils.isTransformable(c, > > > available[i], sourceType)) { > > > - List tail = > > > getConversionPath(destinationType, available[i], > > index + 1, allowNull); > > > + List tail = > > > getConversionPath(destinationType, available[i], > > index + 1); > > > if (tail != null) { > > > tail.add(0, > > available[i]); > > > - return > > tail; > > > + if > > (isPrecise(tail, sourceType, > > > index)) { > > > + > > return tail; > > > + } > > > + > > possibleResult = tail; > > > } > > > } > > > } > > > - return null; > > > + return possibleResult; > > > } > > > > > > + private boolean isPrecise(List > > conversionPath, Class sourceType, > > > int index) { > > > + Transformer[] chain = getChain(); > > > + Class currentSource = sourceType; > > > + int i = 0; > > > + for (Iterator iter = > > conversionPath.iterator(); > > > iter.hasNext(); i++) { > > > + Class currentDest = > > (Class) iter.next(); > > > + if > > (TransformerUtils.isImpreciseConversion(chain[index > > > + i], currentDest, > > > + > > currentSource)) { > > > + return false; > > > + } > > > + currentSource = > > currentDest; > > > + } > > > + return true; > > > + } > > > + > > > /** > > > * Get the components array narrowed to a > > Transformer[]. > > > * @return Transformer[] > > > Index: > > > src/core/net/sf/morph/transform/ImpreciseConverter.java > > > > > > =================================================================== > > > --- > > > src/core/net/sf/morph/transform/ImpreciseConverter.java > > (revision > > > 0) > > > +++ > > > src/core/net/sf/morph/transform/ImpreciseConverter.java > > (revision > > > 0) > > > @@ -0,0 +1,32 @@ > > > +/* > > > + * Copyright 2008 the original author or authors. > > > + * > > > + * 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 net.sf.morph.transform; > > > + > > > +/** > > > + * Defines a converter whose operation may result > > in a loss of data > > > precision. > > > + * > > > + * @author mbenson > > > + * @since Morph 1.0.2 > > > + */ > > > +public interface ImpreciseConverter extends > > Converter { > > > + /** > > > + * Learn whether the specified conversion > > might yield an imprecise > > > result. > > > + * @param destinationClass > > > + * @param sourceClass > > > + * @return boolean > > > + */ > > > + boolean isImpreciseConversion(Class > > destinationClass, Class > > > sourceClass); > > > +} > > > > > > Property changes on: > > > > > > src/core/net/sf/morph/transform/ImpreciseConverter.java > > > > > > ___________________________________________________________________ > > > Name: svn:eol-style > > > + native > > > > > > Index: > > > > > > src/core/net/sf/morph/transform/converters/ObjectToTextConverter.java > > > > > > =================================================================== > > > --- > > > src/core/net/sf/morph/transform/converters/ObjectToTextConverter.java > > > (revision 362) > > > +++ > > > src/core/net/sf/morph/transform/converters/ObjectToTextConverter.java > > > (working copy) > > > @@ -20,7 +20,9 @@ > > > import net.sf.morph.Defaults; > > > import net.sf.morph.transform.Converter; > > > import net.sf.morph.transform.DecoratedConverter; > > > +import net.sf.morph.transform.ImpreciseConverter; > > > import > > net.sf.morph.transform.transformers.BaseTransformer; > > > +import net.sf.morph.util.TransformerUtils; > > > > > > /** > > > * Converts an object to a textual representation > > by calling the object's > > > @@ -32,7 +34,7 @@ > > > * @author Matt Sgarlata > > > * @since Dec 24, 2004 > > > */ > > > -public class ObjectToTextConverter extends > > BaseTransformer implements > > > DecoratedConverter { > > > +public class ObjectToTextConverter extends > > BaseTransformer implements > > > DecoratedConverter, ImpreciseConverter { > > > > > > private Converter textConverter; > > > > > > @@ -52,6 +54,13 @@ > > > /** > > > * {@inheritDoc} > > > */ > > > + protected boolean > > isImpreciseConversionImpl(Class > > > destinationClass, Class sourceClass) { > > > + return > > > TransformerUtils.isImpreciseConversion(getTextConverter(), > > > destinationClass, String.class); > > > + } > > > + > > > + /** > > > + * {@inheritDoc} > > > + */ > > > protected boolean > > isWrappingRuntimeExceptions() { > > > return true; > > > } > > > Index: > > > > > > src/core/net/sf/morph/transform/converters/TextToNumberConverter.java > > > > > > =================================================================== > > > --- > > > src/core/net/sf/morph/transform/converters/TextToNumberConverter.java > > > (revision 361) > > > +++ > > > src/core/net/sf/morph/transform/converters/TextToNumberConverter.java > > > (working copy) > > > @@ -32,7 +32,7 @@ > > > import org.apache.commons.logging.LogFactory; > > > > > > /** > > > - * Converts basic text types into primtive > > numbers or {@link > > > java.lang.Number} > > > + * Converts basic text types into primitive > > numbers or {@link > > > java.lang.Number} > > > * objects. > > > * > > > * @author Matt Sgarlata > > > Index: > > > > > > src/core/net/sf/morph/transform/converters/NumberToTextConverter.java > > > > > > =================================================================== > > > --- > > > src/core/net/sf/morph/transform/converters/NumberToTextConverter.java > > > (revision 363) > > > +++ > > > src/core/net/sf/morph/transform/converters/NumberToTextConverter.java > > > (working copy) > > > @@ -21,7 +21,9 @@ > > > import net.sf.morph.Defaults; > > > import net.sf.morph.transform.Converter; > > > import net.sf.morph.transform.DecoratedConverter; > > > +import net.sf.morph.transform.ImpreciseConverter; > > > import > > net.sf.morph.transform.transformers.BaseTransformer; > > > +import net.sf.morph.util.TransformerUtils; > > > > > > /** > > > * Converts {@link java.lang.Number}s into basic > > text types ({@link > > > java.lang.String}, > > > @@ -30,7 +32,8 @@ > > > * @author Matt Sgarlata > > > * @since Jan 26, 2006 > > > */ > > > -public class NumberToTextConverter extends > > BaseTransformer implements > > > DecoratedConverter { > > > +public class NumberToTextConverter extends > > BaseTransformer implements > > > DecoratedConverter, > > > + ImpreciseConverter { > > > > > > private Converter textConverter; > > > private Converter numberConverter; > > > @@ -58,6 +61,13 @@ > > > } > > > > > > /** > > > + * {@inheritDoc} > > > + */ > > > + protected boolean > > isImpreciseConversionImpl(Class > > > destinationClass, Class sourceClass) { > > > + return > > > TransformerUtils.isImpreciseConversion(getTextConverter(), > > > destinationClass, String.class); > > > + } > > > + > > > + /** > > > * Get the number converter used by this > > NumberToTextConverter. > > > * @return Converter > > > */ > > > Index: > > > src/core/net/sf/morph/transform/converters/TimeToTextConverter.java > > > > > > =================================================================== > > > --- > > > src/core/net/sf/morph/transform/converters/TimeToTextConverter.java > > > (revision 360) > > > +++ > > > src/core/net/sf/morph/transform/converters/TimeToTextConverter.java > > > (working copy) > > > @@ -22,7 +22,9 @@ > > > import net.sf.morph.Defaults; > > > import net.sf.morph.transform.Converter; > > > import net.sf.morph.transform.DecoratedConverter; > > > +import net.sf.morph.transform.ImpreciseConverter; > > > import > > net.sf.morph.transform.transformers.BaseTransformer; > > > +import net.sf.morph.util.TransformerUtils; > > > > > > /** > > > * Converts the basic time types ({@link > > java.util.Date} and > > > @@ -33,7 +35,8 @@ > > > * @author Matt Sgarlata > > > * @since Dec 31, 2004 > > > */ > > > -public class TimeToTextConverter extends > > BaseTransformer implements > > > DecoratedConverter { > > > +public class TimeToTextConverter extends > > BaseTransformer implements > > > DecoratedConverter, > > > + ImpreciseConverter { > > > > > > private DateFormat dateFormat; > > > private Converter timeConverter; > > > @@ -55,6 +58,13 @@ > > > /** > > > * {@inheritDoc} > > > */ > > > + protected boolean > > isImpreciseConversionImpl(Class > > > destinationClass, Class sourceClass) { > > > + return > > > TransformerUtils.isImpreciseConversion(getTextConverter(), > > > destinationClass, String.class); > > > + } > > > + > > > + /** > > > + * {@inheritDoc} > > > + */ > > > protected boolean > > isWrappingRuntimeExceptions() { > > > return true; > > > } > > > Index: > > > src/core/net/sf/morph/transform/converters/TextConverter.java > > > > > > =================================================================== > > > --- > > > src/core/net/sf/morph/transform/converters/TextConverter.java > > > (revision 357) > > > +++ > > > src/core/net/sf/morph/transform/converters/TextConverter.java > > > (working copy) > > > @@ -22,6 +22,7 @@ > > > > > > import net.sf.morph.transform.DecoratedConverter; > > > import > > net.sf.morph.transform.ExplicitTransformer; > > > +import net.sf.morph.transform.ImpreciseConverter; > > > import > > net.sf.morph.transform.TransformationException; > > > import > > net.sf.morph.transform.transformers.BaseTransformer; > > > import net.sf.morph.util.ClassUtils; > > > @@ -43,7 +44,7 @@ > > > * @since Jan 2, 2005 > > > */ > > > public class TextConverter extends > > BaseTransformer implements > > > DecoratedConverter, > > > - ExplicitTransformer { > > > + ExplicitTransformer, > > ImpreciseConverter { > > > > > > private static final Class CHAR_SEQUENCE = > > > ClassUtils.isJdk14OrHigherPresent() ? ClassUtils > > > > > .convertToClass("java.lang.CharSequence") > > > @@ -62,14 +63,7 @@ > > > s.add(Character.class); > > > s.add(char.class); > > > s.add(null); > > > - if (CHAR_SEQUENCE != null) { > > > - s.add(CHAR_SEQUENCE); > > > - try { > > > - > > CONSTRUCTOR_CACHE.put(CHAR_SEQUENCE, > > > StringBuffer.class.getConstructor(new Class[] { > > String.class })); > > > - } catch (Exception e) { > > > - //nope > > > - } > > > - } > > > + s.add(CHAR_SEQUENCE); > > > SOURCE_AND_DESTINATION_TYPES = > > (Class[]) s.toArray(new > > > Class[s.size()]); > > > } > > > > > > @@ -106,7 +100,8 @@ > > > } > > > return new > > Character(string.charAt(0)); > > > } > > > - if (destinationClass == > > String.class) { > > > + if (destinationClass == > > String.class > > > + || > > (destinationClass == CHAR_SEQUENCE && > > > CHAR_SEQUENCE != null)) { > > > return string; > > > } > > > if (destinationClass == > > byte[].class) { > > > @@ -152,6 +147,16 @@ > > > /** > > > * {@inheritDoc} > > > */ > > > + protected boolean > > isImpreciseConversionImpl(Class > > > destinationClass, Class sourceClass) { > > > + if > > (super.isImpreciseConversionImpl(destinationClass, > > > sourceClass)) { > > > + return true; > > > + } > > > + return isChar(destinationClass) && > > !isChar(sourceClass); > > > + } > > > + > > > + /** > > > + * {@inheritDoc} > > > + */ > > > protected boolean > > isAutomaticallyHandlingNulls() { > > > return !isEmptyNull(); > > > } > > > Index: > > > > > > src/core/net/sf/morph/transform/converters/BooleanToTextConverter.java > > > > > > =================================================================== > > > --- > > > src/core/net/sf/morph/transform/converters/BooleanToTextConverter.java > > > (revision 362) > > > +++ > > > src/core/net/sf/morph/transform/converters/BooleanToTextConverter.java > > > (working copy) > > > @@ -20,8 +20,10 @@ > > > import net.sf.morph.Defaults; > > > import net.sf.morph.transform.Converter; > > > import net.sf.morph.transform.DecoratedConverter; > > > +import net.sf.morph.transform.ImpreciseConverter; > > > import > > net.sf.morph.transform.TransformationException; > > > import > > net.sf.morph.transform.transformers.BaseTransformer; > > > +import net.sf.morph.util.TransformerUtils; > > > > > > /** > > > * Converts boolean values to text values. > > Subclasses can build in > > > support for > > > @@ -32,10 +34,10 @@ > > > * @author Matt Sgarlata > > > * @since Jan 9, 2005 > > > */ > > > -public class BooleanToTextConverter extends > > BaseTransformer implements > > > DecoratedConverter { > > > - > > > +public class BooleanToTextConverter extends > > BaseTransformer implements > > > DecoratedConverter, ImpreciseConverter { > > > + > > > private static final Class[] SOURCE_TYPES = > > { Boolean.class, > > > boolean.class }; > > > - > > > + > > > private Converter textConverter; > > > > > > /** > > > @@ -93,9 +95,16 @@ > > > /** > > > * {@inheritDoc} > > > */ > > > + protected boolean > > isImpreciseConversionImpl(Class > > > destinationClass, Class sourceClass) { > > > + return > > > TransformerUtils.isImpreciseConversion(getTextConverter(), > > > destinationClass, String.class); > > > + } > > > + > > > + /** > > > + * {@inheritDoc} > > > + */ > > > protected boolean > > isWrappingRuntimeExceptions() { > > > return true; > > > - } > > > + } > > > > > > /** > > > * Get the text converter used by this > > BaseToPrettyTextConverter. > > > Index: > > > src/core/net/sf/morph/transform/converters/NumberConverter.java > > > > > > =================================================================== > > > --- > > > src/core/net/sf/morph/transform/converters/NumberConverter.java > > > (revision 363) > > > +++ > > > src/core/net/sf/morph/transform/converters/NumberConverter.java > > > (working copy) > > > @@ -19,6 +19,7 @@ > > > import java.util.Locale; > > > > > > import net.sf.morph.transform.DecoratedConverter; > > > +import net.sf.morph.transform.ImpreciseConverter; > > > import > > net.sf.morph.transform.TransformationException; > > > import > > net.sf.morph.transform.support.NumberRounder; > > > import > > net.sf.morph.transform.transformers.BaseTransformer; > > > @@ -31,8 +32,8 @@ > > > * @author Matt Sgarlata > > > * @since Dec 14, 2004 > > > */ > > > -public class NumberConverter extends > > BaseTransformer implements > > > DecoratedConverter { > > > - > > > +public class NumberConverter extends > > BaseTransformer implements > > > DecoratedConverter, ImpreciseConverter { > > > + > > > private static final Class[] > > SOURCE_AND_DESTINATION_TYPES = { > > > Number.class, byte.class, > > short.class, int.class, > > > long.class, > > > float.class, double.class, null > > > @@ -116,9 +117,20 @@ > > > /** > > > * {@inheritDoc} > > > */ > > > + protected boolean > > isImpreciseConversionImpl(Class > > > destinationClass, Class sourceClass) { > > > + return > > super.isImpreciseConversionImpl(destinationClass, > > > sourceClass) > > > + || > > > > > > NumberUtils.NARROWNESS_COMPARATOR.compare(destinationClass, > > > + > > sourceClass) < 0; > > > + } > > > + > > > + /** > > > + * {@inheritDoc} > > > + */ > > > protected Object convertImpl(Class > > destinationClass, Object source, > > > Locale locale) throws Exception { > > > - > > > + if (destinationClass == null) { > > > + return null; > > > + } > > > if (destinationClass.isPrimitive() > > && source == null) { > > > throw new > > TransformationException(destinationClass, > > > source); > > > } > > > Index: > > > > > > src/core/net/sf/morph/transform/converters/BaseToPrettyTextConverter.java > > > > > > =================================================================== > > > --- > > > > > > src/core/net/sf/morph/transform/converters/BaseToPrettyTextConverter.java > > > (revision 362) > > > +++ > > > > > > src/core/net/sf/morph/transform/converters/BaseToPrettyTextConverter.java > > > (working copy) > > > @@ -18,7 +18,9 @@ > > > import net.sf.morph.Defaults; > > > import net.sf.morph.transform.Converter; > > > import net.sf.morph.transform.DecoratedConverter; > > > +import net.sf.morph.transform.ImpreciseConverter; > > > import > > > net.sf.morph.transform.transformers.BaseReflectorTransformer; > > > +import net.sf.morph.util.TransformerUtils; > > > > > > /** > > > * Base class for converts that convert objects to > > a pretty > > > programmer-friendly > > > @@ -27,7 +29,8 @@ > > > * @author Matt Sgarlata > > > * @since Feb 15, 2005 > > > */ > > > -public abstract class BaseToPrettyTextConverter > > extends > > > BaseReflectorTransformer implements > > DecoratedConverter { > > > +public abstract class BaseToPrettyTextConverter > > extends > > > BaseReflectorTransformer > > > + implements DecoratedConverter, > > ImpreciseConverter { > > > > > > private String prefix; > > > private String suffix; > > > @@ -161,4 +164,19 @@ > > > public void setShowNullValues(boolean > > showNullValues) { > > > this.showNullValues = > > showNullValues; > > > } > > > + > > > + /** > > > + * {@inheritDoc} > > > + */ > > > + protected boolean > > isImpreciseConversionImpl(Class > > > destinationClass, Class sourceClass) { > > > + return > > > TransformerUtils.isImpreciseConversion(getTextConverter(), > > > destinationClass, sourceClass); > > > + } > > > + > > > + /** > > > + * Get the intermediate class passed to > > the text converter. > > > + * @return > > > + */ > > > + protected Class getIntermediateClass() { > > > + return StringBuffer.class; > > > + } > > > } > > > Index: src/core/net/sf/morph/util/NumberUtils.java > > > > > > =================================================================== > > > --- src/core/net/sf/morph/util/NumberUtils.java > > (revision 365) > > > +++ src/core/net/sf/morph/util/NumberUtils.java > > (working copy) > > > @@ -19,6 +19,7 @@ > > > import java.lang.reflect.Method; > > > import java.math.BigDecimal; > > > import java.math.BigInteger; > > > +import java.util.Comparator; > > > import java.util.HashMap; > > > import java.util.HashSet; > > > import java.util.Iterator; > > > @@ -69,6 +70,31 @@ > > > } > > > } > > > > > > + private static class NarrownessComparator > > implements Comparator { > > > + /** > > > + * {@inheritDoc} > > > + */ > > > + public int compare(Object arg0, > > Object arg1) { > > > + if (arg0 == arg1) { > > > + return 0; > > > + } > > > + Class c0 = getType(arg0); > > > + Class c1 = getType(arg1); > > > + if (c0 == c1 || c0 == null > > || c1 == null) { > > > + return 0; > > > + } > > > + return > > > > > > getMaximumForType(c0).compareTo(getMaximumForType(c1)); > > > + } > > > + > > > + private Class getType(Object o) { > > > + if > > (MAXIMUMS_FOR_TYPES.containsKey(o)) { > > > + return (Class) o; > > > + } > > > + Class test = > > ClassUtils.getClass(o); > > > + return > > MAXIMUMS_FOR_TYPES.containsKey(test) ? test > > > : null; > > > + } > > > + } > > > + > > > /** > > > * A Map of BigDecimals keyed by Class that > > indicate the maximum > > > value that > > > * the given (Number) Class may taken on. > > > @@ -80,11 +106,16 @@ > > > * the given (Number) Class may taken on. > > > */ > > > public static final Map MINIMUMS_FOR_TYPES; > > > - > > > - public static final Map > > WRAPPERS_FOR_PRIMITIVE_TYPES; > > > > > > - public static final Map NUMBER_FACTORIES; > > > + /** > > > + * Comparator of class/object type > > narrowness. > > > + */ > > > + public static final Comparator > > NARROWNESS_COMPARATOR = new > > > NarrownessComparator(); > > > > > > + private static final Map > > WRAPPERS_FOR_PRIMITIVE_TYPES; > > > + > > > + private static final Map NUMBER_FACTORIES; > > > + > > > /** > > > * Used by {@link > > NumberUtils#isNumber(Class)}. > > > */ > > > Index: > > src/core/net/sf/morph/util/TransformerUtils.java > > > > > > =================================================================== > > > --- > > src/core/net/sf/morph/util/TransformerUtils.java > > (revision 357) > > > +++ > > src/core/net/sf/morph/util/TransformerUtils.java > > (working copy) > > > @@ -1,5 +1,5 @@ > > > /* > > > - * Copyright 2004-2005, 2007 the original author > > or authors. > > > + * Copyright 2004-2005, 2007-2008 the original > > author or authors. > > > * > > > * 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 > > > @@ -26,6 +26,7 @@ > > > import net.sf.morph.transform.Converter; > > > import net.sf.morph.transform.Copier; > > > import > > net.sf.morph.transform.ExplicitTransformer; > > > +import net.sf.morph.transform.ImpreciseConverter; > > > import > > net.sf.morph.transform.TransformationException; > > > import net.sf.morph.transform.Transformer; > > > > > > @@ -90,6 +91,24 @@ > > > } > > > > > > /** > > > + * Learn whether > > <code>transformer</code>'s conversion > > > + * of <code>sourceClass</code> to > > <code>destinationClass</code> > > > might yield an imprecise result. > > > + * @param transformer > > > + * @param destinationClass > > > + * @param sourceClass > > > + * @return boolean > > > + * @see ImpreciseConverter > > > + */ > > > + public static boolean > > isImpreciseConversion(Transformer > > > transformer, > > > + Class destinationClass, > > Class sourceClass) { > > > + if (transformer instanceof > > ImpreciseConverter) { > > > + return > > ((ImpreciseConverter) > > > transformer).isImpreciseConversion( > > > + > > destinationClass, sourceClass); > > > + } > > > + return destinationClass == null && > > sourceClass != null; > > > + } > > > + > > > + /** > > > * Performs a transformation of one object > > graph into another > > > object graph. > > > * > > > * @param destinationType > > > > > > > > > ------------------------------------------------------------------------- > > > This SF.net email is sponsored by: Microsoft > > > Defy all challenges. Microsoft(R) Visual Studio > > 2005. > > > > > > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ > > > _______________________________________________ > > > morph-developer mailing list > > > mor...@li... > > > > > > https://lists.sourceforge.net/lists/listinfo/morph-developer > > > > > > > > > > > > -- > > This message is intended only for the named > > recipient. If you are not the > > intended recipient, you are notified that > > disclosing, copying, distributing, > > or taking any action in reliance on the contents of > > this information is > > strictly prohibited. > > > > ------------------------------------------------------------------------- > > This SF.net email is sponsored by: Microsoft > > Defy all challenges. Microsoft(R) Visual Studio > > 2005. > > > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/> > _______________________________________________ > > morph-developer mailing list > > mor...@li... > > > https://lists.sourceforge.net/lists/listinfo/morph-developer > > > > > > > ____________________________________________________________________________________ > Never miss a thing. Make Yahoo your home page. > http://www.yahoo.com/r/hs > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Microsoft > Defy all challenges. Microsoft(R) Visual Studio 2005. > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ > _______________________________________________ > morph-developer mailing list > mor...@li... > https://lists.sourceforge.net/lists/listinfo/morph-developer > -- This message is intended only for the named recipient. If you are not the intended recipient, you are notified that disclosing, copying, distributing, or taking any action in reliance on the contents of this information is strictly prohibited. |
From: Matt B. <gud...@ya...> - 2008-01-07 16:33:02
|
--- Matt Sgarlata <mat...@sp...> wrote: > I have been thinking more about this approach, and > it's really starting to > grow on me. I do have one concern though, can this > approach be extended to > Copiers? For example, a Map -> Object copy could > probably be considered an > imprecise transformation because the Map may have > more keys than the Object > has properties. > > In addition to your approach, I also like the idea > of cleaning up the > internal implementation in Morph so that ordering of > source and destination > classes is preserved for the following reasons: > 1) for at least some portion of users, setting the > order of source and > destination classes will make sense as an indication > of the transformer's > preferences for performing transformations (so for > this class of users, > creating new transformers that play nicely with the > ChainedTransformerTestCase will be simpler) > 2) I think a general change from using HashSets to > ordered sets in Morph's > implementation will mean transformations happen more > consistently across > JVMs and across time on the same JVM, leading to a > more stable platform > > So, what I did is I basically went through the Morph > codebase and replaced > HashSets with ordered sets (preference order is: JDK > 1.4 LinkedHashSet, > Commons-collections ListOrderedSet, copy of > ListOrderedSet in > net.sf.morph.util). I was never able to modify the > ChainedTransformerTestCase so that it consistently > threw an error. However, > after working on the test case long enough, > eventually something changed in > my environment so that the test started to fail. I > did my change of > HashSets to ordered sets, and that was able to fix > the broken test. I seem to be missing a ClassUtils.isCommonsCollectionsPresent() method after syncing. I'll create my own for now, but it does seem to be missing. Thanks! -Matt B > > I checked in my changes for you to take a look at... > > Matt S > > On Jan 6, 2008 12:59 PM, Matt Benson > <gud...@ya...> wrote: > > > Here's what I've got. > > > > -Matt B > > > > > > > > > ____________________________________________________________________________________ > > Be a better friend, newshound, and > > know-it-all with Yahoo! Mobile. Try it now. > > > http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ > > > > Index: > > > src/core/net/sf/morph/transform/transformers/SimpleDelegatingTransformer.java > > > =================================================================== > > --- > > > src/core/net/sf/morph/transform/transformers/SimpleDelegatingTransformer.java > > (revision 357) > > +++ > > > src/core/net/sf/morph/transform/transformers/SimpleDelegatingTransformer.java > > (working copy) > > @@ -1,5 +1,5 @@ > > /* > > - * Copyright 2004-2005, 2007 the original author > or authors. > > + * Copyright 2004-2005, 2007-2008 the original > author or authors. > > * > > * 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 > > @@ -35,6 +35,7 @@ > > import net.sf.morph.transform.DecoratedConverter; > > import net.sf.morph.transform.DecoratedCopier; > > import > net.sf.morph.transform.ExplicitTransformer; > > +import net.sf.morph.transform.ImpreciseConverter; > > import net.sf.morph.transform.NodeCopier; > > import > net.sf.morph.transform.TransformationException; > > import net.sf.morph.transform.Transformer; > > @@ -93,11 +94,11 @@ > > * @since Dec 12, 2004 > > */ > > public class SimpleDelegatingTransformer extends > BaseCompositeTransformer > > implements > > - SpecializableComposite, > ExplicitTransformer, Transformer, > > DecoratedCopier, DecoratedConverter, Cloneable { > > + SpecializableComposite, > ExplicitTransformer, Transformer, > > DecoratedCopier, > > + DecoratedConverter, Cloneable, > ImpreciseConverter { > > > > //TODO extract BaseDelegatingTransformer > with pluggable delegate > > selection > > > > - > > private static class MapThreadLocal extends > ThreadLocal { > > protected Object initialValue() { > > return new HashMap(); > > @@ -138,6 +139,7 @@ > > } > > > > private Specializer specializer; > > + private boolean preferPreciseTransformers; > > > > private transient ThreadLocal > > visitedSourceToDestinationMapThreadLocal = new > MapThreadLocal(); > > private transient ThreadLocal > stackDepthThreadLocal = new > > StackDepthThreadLocal(); > > @@ -225,6 +227,14 @@ > > > > /** > > * {@inheritDoc} > > + */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + return > TransformerUtils.isImpreciseConversion > > (getTransformer(destinationClass, > > + sourceClass), > destinationClass, > > sourceClass); > > + } > > + > > + /** > > + * {@inheritDoc} > > * @see > > > net.sf.morph.transform.transformers.BaseTransformer#getSourceClassesImpl() > > */ > > protected Class[] getSourceClassesImpl() > throws Exception { > > @@ -477,6 +487,7 @@ > > * if no suitable transformer > could be found > > */ > > private Transformer getTransformer(Class > transformerType, Class > > destinationClass, Class sourceClass) throws > TransformationException { > > + Transformer candidate = null; > > for (int i = 0; i < > components.length; i++) { > > // if the transformer is > the correct type > > Transformer transformer = > (Transformer) > > components[i]; > > @@ -484,6 +495,13 @@ > > // if the > transformer is capable of > > performing the transformation > > if > (TransformerUtils.isTransformable( > > > transformer, > > destinationClass, sourceClass)) { > > + if > (isPreferPreciseTransformers() > > + > && candidate == > > null > > + > && > > > TransformerUtils.isImpreciseConversion(transformer, > > + > > destinationClass, sourceClass)) { > > + > candidate = transformer; > > + > continue; > > + } > > if > (getLog().isTraceEnabled()) { > > > getLog().trace("Using " > > > + > > > ClassUtils.getUnqualifiedClassName(transformerType) > > @@ -496,7 +514,9 @@ > > return > transformer; > > } > > } > > - > > + if (candidate != null) { > > + return candidate; > > + } > > } > > throw new TransformationException( > > "Could not find a > transformer that can transform > > objects of " > > @@ -612,4 +632,20 @@ > > source); > > } > > > > + /** > > + * Get the preferPreciseTransformers. > > + * @return boolean > > + */ > > + public boolean > isPreferPreciseTransformers() { > > + return preferPreciseTransformers; > > + } > > + > > + /** > > + * Set the preferPreciseTransformers. > Default false. > > + * @param preferPreciseTransformers the > boolean to set > > + */ > > + public void > setPreferPreciseTransformers(boolean > > preferPreciseTransformers) { > > + this.preferPreciseTransformers = > > preferPreciseTransformers; > > + } > > + > > } > > \ No newline at end of file > > Index: > src/core/net/sf/morph/transform/transformers/BaseTransformer.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/transformers/BaseTransformer.java > > (revision 358) > > +++ > src/core/net/sf/morph/transform/transformers/BaseTransformer.java > > (working copy) > > @@ -570,6 +570,35 @@ > > } > > } > > > > + /** > > + * Implementation of isImpreciseConversion > > + * @param destinationClass > > + * @param sourceClass > > + * @return > > + */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + return destinationClass == null && > sourceClass != null; > > + } > > + > > + /** > > + * Learn whether the specified conversion > yields an imprecise > > result. > > + * @param destinationClass > > + * @param sourceClass > > + * @return boolean > > + */ > > + public final boolean > isImpreciseConversion(Class destinationClass, > > Class sourceClass) { > > + try { > > + return > isImpreciseConversionImpl(destinationClass, > > sourceClass); > > + } catch (Exception e) { > > + if (e instanceof > RuntimeException && > > !isWrappingRuntimeExceptions()) { > > + throw > (RuntimeException) e; > > + } > > + throw new > TransformationException("Could not > > determine if conversion of " > > + + > sourceClass + " to " + > > destinationClass > > + + " > results in a loss of > > precision", e); > > + } > > + } > > + > > // property getters and setters > > > > /** > > Index: > > > src/core/net/sf/morph/transform/transformers/ChainedTransformer.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/transformers/ChainedTransformer.java > > (revision 357) > > +++ > src/core/net/sf/morph/transform/transformers/ChainedTransformer.java > > (working copy) > > @@ -1,5 +1,5 @@ > > /* > > - * Copyright 2004-2005, 2007 the original author > or authors. > > + * Copyright 2004-2005, 2007-2008 the original > author or authors. > > * > > * 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 > > @@ -16,6 +16,7 @@ > > package net.sf.morph.transform.transformers; > > > > import java.util.ArrayList; > > +import java.util.Iterator; > > import java.util.List; > > import java.util.Locale; > > > > @@ -25,6 +26,7 @@ > > import net.sf.morph.transform.DecoratedConverter; > > import net.sf.morph.transform.DecoratedCopier; > > import > net.sf.morph.transform.ExplicitTransformer; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.TransformationException; > > import net.sf.morph.transform.Transformer; > > import > net.sf.morph.transform.copiers.CopierDecorator; > > @@ -40,7 +42,7 @@ > > * @since Nov 24, 2004 > > */ > > public class ChainedTransformer extends > BaseCompositeTransformer > > implements > > - DecoratedConverter, > DecoratedCopier, ExplicitTransformer { > > + DecoratedConverter, > DecoratedCopier, ExplicitTransformer, > > ImpreciseConverter { > > > > private Converter copyConverter; > > > > @@ -67,6 +69,14 @@ > > } > > > > /** > > + * {@inheritDoc} > > + */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + List conversionPath = > getConversionPath(destinationClass, > > sourceClass); > > + return !isPrecise(conversionPath, > sourceClass, 0); > > + } > > + > > + /** > > * Get the converter used when using a > ChainedTransformer as a > > Copier. > > * @return > > */ > > @@ -113,6 +123,7 @@ > > throw new > TransformationException(destinationClass, > > sourceType, null, > > "Chained > conversion path could not > > be determined"); > > } > > + log.debug("Using chained > conversion path " + > > conversionPath); > > Object o = source; > > for (int i = 0; i < > conversionPath.size(); i++) { > > o = > getConverter(chain[i]).convert((Class) > > conversionPath.get(i), o, locale); > > @@ -144,6 +155,7 @@ > > throw new > TransformationException(destinationClass, > > source, null, > > "Chained > conversion path could not > > be determined"); > > } > > + log.debug("Using chained > conversion path " + > > conversionPath); > > Object last = > getCopyConverter().convert((Class) > > conversionPath.get(chain.length - 2), source, > locale); > > ((Copier) copier).copy(destination, > last, locale); > > } > > @@ -192,13 +204,7 @@ > > * @return List > > */ > > protected List getConversionPath(Class > destinationType, Class > > sourceType) { > > - if (sourceType != null) { > > - List withoutNull = > > getConversionPath(destinationType, sourceType, 0, > false); > > - if (withoutNull != null) { > > - return > withoutNull; > > - } > > - } > > - return > getConversionPath(destinationType, sourceType, 0, > > true); > > + return > getConversionPath(destinationType, sourceType, 0); > > } > > > > /** > > @@ -210,7 +216,7 @@ > > * @param allowNull > > * @return List > > */ > > - private List getConversionPath(Class > destinationType, Class > > sourceType, int index, boolean allowNull) { > > + private List getConversionPath(Class > destinationType, Class > > sourceType, int index) { > > Transformer[] chain = getChain(); > > Transformer c = chain[index]; > > if (index + 1 == chain.length) { > > @@ -221,22 +227,38 @@ > > } > > return null; > > } > > + List possibleResult = null; > > Class[] available = > c.getDestinationClasses(); > > for (int i = 0; i < > available.length; i++) { > > - if (available[i] == null > && !allowNull) { > > - continue; > > - } > > if > (TransformerUtils.isTransformable(c, > > available[i], sourceType)) { > > - List tail = > > getConversionPath(destinationType, available[i], > index + 1, allowNull); > > + List tail = > > getConversionPath(destinationType, available[i], > index + 1); > > if (tail != null) { > > tail.add(0, > available[i]); > > - return > tail; > > + if > (isPrecise(tail, sourceType, > > index)) { > > + > return tail; > > + } > > + > possibleResult = tail; > > } > > } > > } > > - return null; > > + return possibleResult; > > } > > > > + private boolean isPrecise(List > conversionPath, Class sourceType, > > int index) { > > + Transformer[] chain = getChain(); > > + Class currentSource = sourceType; > > + int i = 0; > > + for (Iterator iter = > conversionPath.iterator(); > > iter.hasNext(); i++) { > > + Class currentDest = > (Class) iter.next(); > > + if > (TransformerUtils.isImpreciseConversion(chain[index > > + i], currentDest, > > + > currentSource)) { > > + return false; > > + } > > + currentSource = > currentDest; > > + } > > + return true; > > + } > > + > > /** > > * Get the components array narrowed to a > Transformer[]. > > * @return Transformer[] > > Index: > src/core/net/sf/morph/transform/ImpreciseConverter.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/ImpreciseConverter.java > (revision > > 0) > > +++ > src/core/net/sf/morph/transform/ImpreciseConverter.java > (revision > > 0) > > @@ -0,0 +1,32 @@ > > +/* > > + * Copyright 2008 the original author or authors. > > + * > > + * 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 net.sf.morph.transform; > > + > > +/** > > + * Defines a converter whose operation may result > in a loss of data > > precision. > > + * > > + * @author mbenson > > + * @since Morph 1.0.2 > > + */ > > +public interface ImpreciseConverter extends > Converter { > > + /** > > + * Learn whether the specified conversion > might yield an imprecise > > result. > > + * @param destinationClass > > + * @param sourceClass > > + * @return boolean > > + */ > > + boolean isImpreciseConversion(Class > destinationClass, Class > > sourceClass); > > +} > > > > Property changes on: > > > src/core/net/sf/morph/transform/ImpreciseConverter.java > > > ___________________________________________________________________ > > Name: svn:eol-style > > + native > > > > Index: > > > src/core/net/sf/morph/transform/converters/ObjectToTextConverter.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/converters/ObjectToTextConverter.java > > (revision 362) > > +++ > src/core/net/sf/morph/transform/converters/ObjectToTextConverter.java > > (working copy) > > @@ -20,7 +20,9 @@ > > import net.sf.morph.Defaults; > > import net.sf.morph.transform.Converter; > > import net.sf.morph.transform.DecoratedConverter; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.transformers.BaseTransformer; > > +import net.sf.morph.util.TransformerUtils; > > > > /** > > * Converts an object to a textual representation > by calling the object's > > @@ -32,7 +34,7 @@ > > * @author Matt Sgarlata > > * @since Dec 24, 2004 > > */ > > -public class ObjectToTextConverter extends > BaseTransformer implements > > DecoratedConverter { > > +public class ObjectToTextConverter extends > BaseTransformer implements > > DecoratedConverter, ImpreciseConverter { > > > > private Converter textConverter; > > > > @@ -52,6 +54,13 @@ > > /** > > * {@inheritDoc} > > */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + return > TransformerUtils.isImpreciseConversion(getTextConverter(), > > destinationClass, String.class); > > + } > > + > > + /** > > + * {@inheritDoc} > > + */ > > protected boolean > isWrappingRuntimeExceptions() { > > return true; > > } > > Index: > > > src/core/net/sf/morph/transform/converters/TextToNumberConverter.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/converters/TextToNumberConverter.java > > (revision 361) > > +++ > src/core/net/sf/morph/transform/converters/TextToNumberConverter.java > > (working copy) > > @@ -32,7 +32,7 @@ > > import org.apache.commons.logging.LogFactory; > > > > /** > > - * Converts basic text types into primtive > numbers or {@link > > java.lang.Number} > > + * Converts basic text types into primitive > numbers or {@link > > java.lang.Number} > > * objects. > > * > > * @author Matt Sgarlata > > Index: > > > src/core/net/sf/morph/transform/converters/NumberToTextConverter.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/converters/NumberToTextConverter.java > > (revision 363) > > +++ > src/core/net/sf/morph/transform/converters/NumberToTextConverter.java > > (working copy) > > @@ -21,7 +21,9 @@ > > import net.sf.morph.Defaults; > > import net.sf.morph.transform.Converter; > > import net.sf.morph.transform.DecoratedConverter; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.transformers.BaseTransformer; > > +import net.sf.morph.util.TransformerUtils; > > > > /** > > * Converts {@link java.lang.Number}s into basic > text types ({@link > > java.lang.String}, > > @@ -30,7 +32,8 @@ > > * @author Matt Sgarlata > > * @since Jan 26, 2006 > > */ > > -public class NumberToTextConverter extends > BaseTransformer implements > > DecoratedConverter { > > +public class NumberToTextConverter extends > BaseTransformer implements > > DecoratedConverter, > > + ImpreciseConverter { > > > > private Converter textConverter; > > private Converter numberConverter; > > @@ -58,6 +61,13 @@ > > } > > > > /** > > + * {@inheritDoc} > > + */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + return > TransformerUtils.isImpreciseConversion(getTextConverter(), > > destinationClass, String.class); > > + } > > + > > + /** > > * Get the number converter used by this > NumberToTextConverter. > > * @return Converter > > */ > > Index: > src/core/net/sf/morph/transform/converters/TimeToTextConverter.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/converters/TimeToTextConverter.java > > (revision 360) > > +++ > src/core/net/sf/morph/transform/converters/TimeToTextConverter.java > > (working copy) > > @@ -22,7 +22,9 @@ > > import net.sf.morph.Defaults; > > import net.sf.morph.transform.Converter; > > import net.sf.morph.transform.DecoratedConverter; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.transformers.BaseTransformer; > > +import net.sf.morph.util.TransformerUtils; > > > > /** > > * Converts the basic time types ({@link > java.util.Date} and > > @@ -33,7 +35,8 @@ > > * @author Matt Sgarlata > > * @since Dec 31, 2004 > > */ > > -public class TimeToTextConverter extends > BaseTransformer implements > > DecoratedConverter { > > +public class TimeToTextConverter extends > BaseTransformer implements > > DecoratedConverter, > > + ImpreciseConverter { > > > > private DateFormat dateFormat; > > private Converter timeConverter; > > @@ -55,6 +58,13 @@ > > /** > > * {@inheritDoc} > > */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + return > TransformerUtils.isImpreciseConversion(getTextConverter(), > > destinationClass, String.class); > > + } > > + > > + /** > > + * {@inheritDoc} > > + */ > > protected boolean > isWrappingRuntimeExceptions() { > > return true; > > } > > Index: > src/core/net/sf/morph/transform/converters/TextConverter.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/converters/TextConverter.java > > (revision 357) > > +++ > src/core/net/sf/morph/transform/converters/TextConverter.java > > (working copy) > > @@ -22,6 +22,7 @@ > > > > import net.sf.morph.transform.DecoratedConverter; > > import > net.sf.morph.transform.ExplicitTransformer; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.TransformationException; > > import > net.sf.morph.transform.transformers.BaseTransformer; > > import net.sf.morph.util.ClassUtils; > > @@ -43,7 +44,7 @@ > > * @since Jan 2, 2005 > > */ > > public class TextConverter extends > BaseTransformer implements > > DecoratedConverter, > > - ExplicitTransformer { > > + ExplicitTransformer, > ImpreciseConverter { > > > > private static final Class CHAR_SEQUENCE = > > ClassUtils.isJdk14OrHigherPresent() ? ClassUtils > > > .convertToClass("java.lang.CharSequence") > > @@ -62,14 +63,7 @@ > > s.add(Character.class); > > s.add(char.class); > > s.add(null); > > - if (CHAR_SEQUENCE != null) { > > - s.add(CHAR_SEQUENCE); > > - try { > > - > CONSTRUCTOR_CACHE.put(CHAR_SEQUENCE, > > StringBuffer.class.getConstructor(new Class[] { > String.class })); > > - } catch (Exception e) { > > - //nope > > - } > > - } > > + s.add(CHAR_SEQUENCE); > > SOURCE_AND_DESTINATION_TYPES = > (Class[]) s.toArray(new > > Class[s.size()]); > > } > > > > @@ -106,7 +100,8 @@ > > } > > return new > Character(string.charAt(0)); > > } > > - if (destinationClass == > String.class) { > > + if (destinationClass == > String.class > > + || > (destinationClass == CHAR_SEQUENCE && > > CHAR_SEQUENCE != null)) { > > return string; > > } > > if (destinationClass == > byte[].class) { > > @@ -152,6 +147,16 @@ > > /** > > * {@inheritDoc} > > */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + if > (super.isImpreciseConversionImpl(destinationClass, > > sourceClass)) { > > + return true; > > + } > > + return isChar(destinationClass) && > !isChar(sourceClass); > > + } > > + > > + /** > > + * {@inheritDoc} > > + */ > > protected boolean > isAutomaticallyHandlingNulls() { > > return !isEmptyNull(); > > } > > Index: > > > src/core/net/sf/morph/transform/converters/BooleanToTextConverter.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/converters/BooleanToTextConverter.java > > (revision 362) > > +++ > src/core/net/sf/morph/transform/converters/BooleanToTextConverter.java > > (working copy) > > @@ -20,8 +20,10 @@ > > import net.sf.morph.Defaults; > > import net.sf.morph.transform.Converter; > > import net.sf.morph.transform.DecoratedConverter; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.TransformationException; > > import > net.sf.morph.transform.transformers.BaseTransformer; > > +import net.sf.morph.util.TransformerUtils; > > > > /** > > * Converts boolean values to text values. > Subclasses can build in > > support for > > @@ -32,10 +34,10 @@ > > * @author Matt Sgarlata > > * @since Jan 9, 2005 > > */ > > -public class BooleanToTextConverter extends > BaseTransformer implements > > DecoratedConverter { > > - > > +public class BooleanToTextConverter extends > BaseTransformer implements > > DecoratedConverter, ImpreciseConverter { > > + > > private static final Class[] SOURCE_TYPES = > { Boolean.class, > > boolean.class }; > > - > > + > > private Converter textConverter; > > > > /** > > @@ -93,9 +95,16 @@ > > /** > > * {@inheritDoc} > > */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + return > TransformerUtils.isImpreciseConversion(getTextConverter(), > > destinationClass, String.class); > > + } > > + > > + /** > > + * {@inheritDoc} > > + */ > > protected boolean > isWrappingRuntimeExceptions() { > > return true; > > - } > > + } > > > > /** > > * Get the text converter used by this > BaseToPrettyTextConverter. > > Index: > src/core/net/sf/morph/transform/converters/NumberConverter.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/converters/NumberConverter.java > > (revision 363) > > +++ > src/core/net/sf/morph/transform/converters/NumberConverter.java > > (working copy) > > @@ -19,6 +19,7 @@ > > import java.util.Locale; > > > > import net.sf.morph.transform.DecoratedConverter; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.TransformationException; > > import > net.sf.morph.transform.support.NumberRounder; > > import > net.sf.morph.transform.transformers.BaseTransformer; > > @@ -31,8 +32,8 @@ > > * @author Matt Sgarlata > > * @since Dec 14, 2004 > > */ > > -public class NumberConverter extends > BaseTransformer implements > > DecoratedConverter { > > - > > +public class NumberConverter extends > BaseTransformer implements > > DecoratedConverter, ImpreciseConverter { > > + > > private static final Class[] > SOURCE_AND_DESTINATION_TYPES = { > > Number.class, byte.class, > short.class, int.class, > > long.class, > > float.class, double.class, null > > @@ -116,9 +117,20 @@ > > /** > > * {@inheritDoc} > > */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + return > super.isImpreciseConversionImpl(destinationClass, > > sourceClass) > > + || > > > NumberUtils.NARROWNESS_COMPARATOR.compare(destinationClass, > > + > sourceClass) < 0; > > + } > > + > > + /** > > + * {@inheritDoc} > > + */ > > protected Object convertImpl(Class > destinationClass, Object source, > > Locale locale) throws Exception { > > - > > + if (destinationClass == null) { > > + return null; > > + } > > if (destinationClass.isPrimitive() > && source == null) { > > throw new > TransformationException(destinationClass, > > source); > > } > > Index: > > > src/core/net/sf/morph/transform/converters/BaseToPrettyTextConverter.java > > > =================================================================== > > --- > > > src/core/net/sf/morph/transform/converters/BaseToPrettyTextConverter.java > > (revision 362) > > +++ > > > src/core/net/sf/morph/transform/converters/BaseToPrettyTextConverter.java > > (working copy) > > @@ -18,7 +18,9 @@ > > import net.sf.morph.Defaults; > > import net.sf.morph.transform.Converter; > > import net.sf.morph.transform.DecoratedConverter; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.transformers.BaseReflectorTransformer; > > +import net.sf.morph.util.TransformerUtils; > > > > /** > > * Base class for converts that convert objects to > a pretty > > programmer-friendly > > @@ -27,7 +29,8 @@ > > * @author Matt Sgarlata > > * @since Feb 15, 2005 > > */ > > -public abstract class BaseToPrettyTextConverter > extends > > BaseReflectorTransformer implements > DecoratedConverter { > > +public abstract class BaseToPrettyTextConverter > extends > > BaseReflectorTransformer > > + implements DecoratedConverter, > ImpreciseConverter { > > > > private String prefix; > > private String suffix; > > @@ -161,4 +164,19 @@ > > public void setShowNullValues(boolean > showNullValues) { > > this.showNullValues = > showNullValues; > > } > > + > > + /** > > + * {@inheritDoc} > > + */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + return > TransformerUtils.isImpreciseConversion(getTextConverter(), > > destinationClass, sourceClass); > > + } > > + > > + /** > > + * Get the intermediate class passed to > the text converter. > > + * @return > > + */ > > + protected Class getIntermediateClass() { > > + return StringBuffer.class; > > + } > > } > > Index: src/core/net/sf/morph/util/NumberUtils.java > > > =================================================================== > > --- src/core/net/sf/morph/util/NumberUtils.java > (revision 365) > > +++ src/core/net/sf/morph/util/NumberUtils.java > (working copy) > > @@ -19,6 +19,7 @@ > > import java.lang.reflect.Method; > > import java.math.BigDecimal; > > import java.math.BigInteger; > > +import java.util.Comparator; > > import java.util.HashMap; > > import java.util.HashSet; > > import java.util.Iterator; > > @@ -69,6 +70,31 @@ > > } > > } > > > > + private static class NarrownessComparator > implements Comparator { > > + /** > > + * {@inheritDoc} > > + */ > > + public int compare(Object arg0, > Object arg1) { > > + if (arg0 == arg1) { > > + return 0; > > + } > > + Class c0 = getType(arg0); > > + Class c1 = getType(arg1); > > + if (c0 == c1 || c0 == null > || c1 == null) { > > + return 0; > > + } > > + return > > > getMaximumForType(c0).compareTo(getMaximumForType(c1)); > > + } > > + > > + private Class getType(Object o) { > > + if > (MAXIMUMS_FOR_TYPES.containsKey(o)) { > > + return (Class) o; > > + } > > + Class test = > ClassUtils.getClass(o); > > + return > MAXIMUMS_FOR_TYPES.containsKey(test) ? test > > : null; > > + } > > + } > > + > > /** > > * A Map of BigDecimals keyed by Class that > indicate the maximum > > value that > > * the given (Number) Class may taken on. > > @@ -80,11 +106,16 @@ > > * the given (Number) Class may taken on. > > */ > > public static final Map MINIMUMS_FOR_TYPES; > > - > > - public static final Map > WRAPPERS_FOR_PRIMITIVE_TYPES; > > > > - public static final Map NUMBER_FACTORIES; > > + /** > > + * Comparator of class/object type > narrowness. > > + */ > > + public static final Comparator > NARROWNESS_COMPARATOR = new > > NarrownessComparator(); > > > > + private static final Map > WRAPPERS_FOR_PRIMITIVE_TYPES; > > + > > + private static final Map NUMBER_FACTORIES; > > + > > /** > > * Used by {@link > NumberUtils#isNumber(Class)}. > > */ > > Index: > src/core/net/sf/morph/util/TransformerUtils.java > > > =================================================================== > > --- > src/core/net/sf/morph/util/TransformerUtils.java > (revision 357) > > +++ > src/core/net/sf/morph/util/TransformerUtils.java > (working copy) > > @@ -1,5 +1,5 @@ > > /* > > - * Copyright 2004-2005, 2007 the original author > or authors. > > + * Copyright 2004-2005, 2007-2008 the original > author or authors. > > * > > * 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 > > @@ -26,6 +26,7 @@ > > import net.sf.morph.transform.Converter; > > import net.sf.morph.transform.Copier; > > import > net.sf.morph.transform.ExplicitTransformer; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.TransformationException; > > import net.sf.morph.transform.Transformer; > > > > @@ -90,6 +91,24 @@ > > } > > > > /** > > + * Learn whether > <code>transformer</code>'s conversion > > + * of <code>sourceClass</code> to > <code>destinationClass</code> > > might yield an imprecise result. > > + * @param transformer > > + * @param destinationClass > > + * @param sourceClass > > + * @return boolean > > + * @see ImpreciseConverter > > + */ > > + public static boolean > isImpreciseConversion(Transformer > > transformer, > > + Class destinationClass, > Class sourceClass) { > > + if (transformer instanceof > ImpreciseConverter) { > > + return > ((ImpreciseConverter) > > transformer).isImpreciseConversion( > > + > destinationClass, sourceClass); > > + } > > + return destinationClass == null && > sourceClass != null; > > + } > > + > > + /** > > * Performs a transformation of one object > graph into another > > object graph. > > * > > * @param destinationType > > > > > ------------------------------------------------------------------------- > > This SF.net email is sponsored by: Microsoft > > Defy all challenges. Microsoft(R) Visual Studio > 2005. > > > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ > > _______________________________________________ > > morph-developer mailing list > > mor...@li... > > > https://lists.sourceforge.net/lists/listinfo/morph-developer > > > > > > > -- > This message is intended only for the named > recipient. If you are not the > intended recipient, you are notified that > disclosing, copying, distributing, > or taking any action in reliance on the contents of > this information is > strictly prohibited. > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Microsoft > Defy all challenges. Microsoft(R) Visual Studio > 2005. > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/> _______________________________________________ > morph-developer mailing list > mor...@li... > https://lists.sourceforge.net/lists/listinfo/morph-developer > ____________________________________________________________________________________ Never miss a thing. Make Yahoo your home page. http://www.yahoo.com/r/hs |
From: Matt B. <gud...@ya...> - 2008-01-07 16:10:57
|
--- Matt Sgarlata <mat...@sp...> wrote: > I have been thinking more about this approach, and > it's really starting to > grow on me. I do have one concern though, can this > approach be extended to > Copiers? For example, a Map -> Object copy could > probably be considered an > imprecise transformation because the Map may have > more keys than the Object > has properties. I thought about this as well. It could be done; it might be slightly complex calculating the "precision" of a PropertyNameMatchingCopier--I would think an explicitly specified PNMatchingC would be precise; an imprecise one would be one using property name discovery and where the properties of the source are not all available on the destination. There--the hard part of that one is over. :) I will work on ImpreciseConverter -> ImpreciseTransformer extends Transformer and other semantic changes as time permits. Your ordering changes are, I expect, fine by me as well. :) -Matt B > > In addition to your approach, I also like the idea > of cleaning up the > internal implementation in Morph so that ordering of > source and destination > classes is preserved for the following reasons: > 1) for at least some portion of users, setting the > order of source and > destination classes will make sense as an indication > of the transformer's > preferences for performing transformations (so for > this class of users, > creating new transformers that play nicely with the > ChainedTransformerTestCase will be simpler) > 2) I think a general change from using HashSets to > ordered sets in Morph's > implementation will mean transformations happen more > consistently across > JVMs and across time on the same JVM, leading to a > more stable platform > > So, what I did is I basically went through the Morph > codebase and replaced > HashSets with ordered sets (preference order is: JDK > 1.4 LinkedHashSet, > Commons-collections ListOrderedSet, copy of > ListOrderedSet in > net.sf.morph.util). I was never able to modify the > ChainedTransformerTestCase so that it consistently > threw an error. However, > after working on the test case long enough, > eventually something changed in > my environment so that the test started to fail. I > did my change of > HashSets to ordered sets, and that was able to fix > the broken test. > > I checked in my changes for you to take a look at... > > Matt S > > On Jan 6, 2008 12:59 PM, Matt Benson > <gud...@ya...> wrote: > > > Here's what I've got. > > > > -Matt B > > > > > > > > > ____________________________________________________________________________________ > > Be a better friend, newshound, and > > know-it-all with Yahoo! Mobile. Try it now. > > > http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ > > > > Index: > > > src/core/net/sf/morph/transform/transformers/SimpleDelegatingTransformer.java > > > =================================================================== > > --- > > > src/core/net/sf/morph/transform/transformers/SimpleDelegatingTransformer.java > > (revision 357) > > +++ > > > src/core/net/sf/morph/transform/transformers/SimpleDelegatingTransformer.java > > (working copy) > > @@ -1,5 +1,5 @@ > > /* > > - * Copyright 2004-2005, 2007 the original author > or authors. > > + * Copyright 2004-2005, 2007-2008 the original > author or authors. > > * > > * 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 > > @@ -35,6 +35,7 @@ > > import net.sf.morph.transform.DecoratedConverter; > > import net.sf.morph.transform.DecoratedCopier; > > import > net.sf.morph.transform.ExplicitTransformer; > > +import net.sf.morph.transform.ImpreciseConverter; > > import net.sf.morph.transform.NodeCopier; > > import > net.sf.morph.transform.TransformationException; > > import net.sf.morph.transform.Transformer; > > @@ -93,11 +94,11 @@ > > * @since Dec 12, 2004 > > */ > > public class SimpleDelegatingTransformer extends > BaseCompositeTransformer > > implements > > - SpecializableComposite, > ExplicitTransformer, Transformer, > > DecoratedCopier, DecoratedConverter, Cloneable { > > + SpecializableComposite, > ExplicitTransformer, Transformer, > > DecoratedCopier, > > + DecoratedConverter, Cloneable, > ImpreciseConverter { > > > > //TODO extract BaseDelegatingTransformer > with pluggable delegate > > selection > > > > - > > private static class MapThreadLocal extends > ThreadLocal { > > protected Object initialValue() { > > return new HashMap(); > > @@ -138,6 +139,7 @@ > > } > > > > private Specializer specializer; > > + private boolean preferPreciseTransformers; > > > > private transient ThreadLocal > > visitedSourceToDestinationMapThreadLocal = new > MapThreadLocal(); > > private transient ThreadLocal > stackDepthThreadLocal = new > > StackDepthThreadLocal(); > > @@ -225,6 +227,14 @@ > > > > /** > > * {@inheritDoc} > > + */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + return > TransformerUtils.isImpreciseConversion > > (getTransformer(destinationClass, > > + sourceClass), > destinationClass, > > sourceClass); > > + } > > + > > + /** > > + * {@inheritDoc} > > * @see > > > net.sf.morph.transform.transformers.BaseTransformer#getSourceClassesImpl() > > */ > > protected Class[] getSourceClassesImpl() > throws Exception { > > @@ -477,6 +487,7 @@ > > * if no suitable transformer > could be found > > */ > > private Transformer getTransformer(Class > transformerType, Class > > destinationClass, Class sourceClass) throws > TransformationException { > > + Transformer candidate = null; > > for (int i = 0; i < > components.length; i++) { > > // if the transformer is > the correct type > > Transformer transformer = > (Transformer) > > components[i]; > > @@ -484,6 +495,13 @@ > > // if the > transformer is capable of > > performing the transformation > > if > (TransformerUtils.isTransformable( > > > transformer, > > destinationClass, sourceClass)) { > > + if > (isPreferPreciseTransformers() > > + > && candidate == > > null > > + > && > > > TransformerUtils.isImpreciseConversion(transformer, > > + > > destinationClass, sourceClass)) { > > + > candidate = transformer; > > + > continue; > > + } > > if > (getLog().isTraceEnabled()) { > > > getLog().trace("Using " > > > + > > > ClassUtils.getUnqualifiedClassName(transformerType) > > @@ -496,7 +514,9 @@ > > return > transformer; > > } > > } > > - > > + if (candidate != null) { > > + return candidate; > > + } > > } > > throw new TransformationException( > > "Could not find a > transformer that can transform > > objects of " > > @@ -612,4 +632,20 @@ > > source); > > } > > > > + /** > > + * Get the preferPreciseTransformers. > > + * @return boolean > > + */ > > + public boolean > isPreferPreciseTransformers() { > > + return preferPreciseTransformers; > > + } > > + > > + /** > > + * Set the preferPreciseTransformers. > Default false. > > + * @param preferPreciseTransformers the > boolean to set > > + */ > > + public void > setPreferPreciseTransformers(boolean > > preferPreciseTransformers) { > > + this.preferPreciseTransformers = > > preferPreciseTransformers; > > + } > > + > > } > > \ No newline at end of file > > Index: > src/core/net/sf/morph/transform/transformers/BaseTransformer.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/transformers/BaseTransformer.java > > (revision 358) > > +++ > src/core/net/sf/morph/transform/transformers/BaseTransformer.java > > (working copy) > > @@ -570,6 +570,35 @@ > > } > > } > > > > + /** > > + * Implementation of isImpreciseConversion > > + * @param destinationClass > > + * @param sourceClass > > + * @return > > + */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + return destinationClass == null && > sourceClass != null; > > + } > > + > > + /** > > + * Learn whether the specified conversion > yields an imprecise > > result. > > + * @param destinationClass > > + * @param sourceClass > > + * @return boolean > > + */ > > + public final boolean > isImpreciseConversion(Class destinationClass, > > Class sourceClass) { > > + try { > > + return > isImpreciseConversionImpl(destinationClass, > > sourceClass); > > + } catch (Exception e) { > > + if (e instanceof > RuntimeException && > > !isWrappingRuntimeExceptions()) { > > + throw > (RuntimeException) e; > > + } > > + throw new > TransformationException("Could not > > determine if conversion of " > > + + > sourceClass + " to " + > > destinationClass > > + + " > results in a loss of > > precision", e); > > + } > > + } > > + > > // property getters and setters > > > > /** > > Index: > > > src/core/net/sf/morph/transform/transformers/ChainedTransformer.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/transformers/ChainedTransformer.java > > (revision 357) > > +++ > src/core/net/sf/morph/transform/transformers/ChainedTransformer.java > > (working copy) > > @@ -1,5 +1,5 @@ > > /* > > - * Copyright 2004-2005, 2007 the original author > or authors. > > + * Copyright 2004-2005, 2007-2008 the original > author or authors. > > * > > * 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 > > @@ -16,6 +16,7 @@ > > package net.sf.morph.transform.transformers; > > > > import java.util.ArrayList; > > +import java.util.Iterator; > > import java.util.List; > > import java.util.Locale; > > > > @@ -25,6 +26,7 @@ > > import net.sf.morph.transform.DecoratedConverter; > > import net.sf.morph.transform.DecoratedCopier; > > import > net.sf.morph.transform.ExplicitTransformer; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.TransformationException; > > import net.sf.morph.transform.Transformer; > > import > net.sf.morph.transform.copiers.CopierDecorator; > > @@ -40,7 +42,7 @@ > > * @since Nov 24, 2004 > > */ > > public class ChainedTransformer extends > BaseCompositeTransformer > > implements > > - DecoratedConverter, > DecoratedCopier, ExplicitTransformer { > > + DecoratedConverter, > DecoratedCopier, ExplicitTransformer, > > ImpreciseConverter { > > > > private Converter copyConverter; > > > > @@ -67,6 +69,14 @@ > > } > > > > /** > > + * {@inheritDoc} > > + */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + List conversionPath = > getConversionPath(destinationClass, > > sourceClass); > > + return !isPrecise(conversionPath, > sourceClass, 0); > > + } > > + > > + /** > > * Get the converter used when using a > ChainedTransformer as a > > Copier. > > * @return > > */ > > @@ -113,6 +123,7 @@ > > throw new > TransformationException(destinationClass, > > sourceType, null, > > "Chained > conversion path could not > > be determined"); > > } > > + log.debug("Using chained > conversion path " + > > conversionPath); > > Object o = source; > > for (int i = 0; i < > conversionPath.size(); i++) { > > o = > getConverter(chain[i]).convert((Class) > > conversionPath.get(i), o, locale); > > @@ -144,6 +155,7 @@ > > throw new > TransformationException(destinationClass, > > source, null, > > "Chained > conversion path could not > > be determined"); > > } > > + log.debug("Using chained > conversion path " + > > conversionPath); > > Object last = > getCopyConverter().convert((Class) > > conversionPath.get(chain.length - 2), source, > locale); > > ((Copier) copier).copy(destination, > last, locale); > > } > > @@ -192,13 +204,7 @@ > > * @return List > > */ > > protected List getConversionPath(Class > destinationType, Class > > sourceType) { > > - if (sourceType != null) { > > - List withoutNull = > > getConversionPath(destinationType, sourceType, 0, > false); > > - if (withoutNull != null) { > > - return > withoutNull; > > - } > > - } > > - return > getConversionPath(destinationType, sourceType, 0, > > true); > > + return > getConversionPath(destinationType, sourceType, 0); > > } > > > > /** > > @@ -210,7 +216,7 @@ > > * @param allowNull > > * @return List > > */ > > - private List getConversionPath(Class > destinationType, Class > > sourceType, int index, boolean allowNull) { > > + private List getConversionPath(Class > destinationType, Class > > sourceType, int index) { > > Transformer[] chain = getChain(); > > Transformer c = chain[index]; > > if (index + 1 == chain.length) { > > @@ -221,22 +227,38 @@ > > } > > return null; > > } > > + List possibleResult = null; > > Class[] available = > c.getDestinationClasses(); > > for (int i = 0; i < > available.length; i++) { > > - if (available[i] == null > && !allowNull) { > > - continue; > > - } > > if > (TransformerUtils.isTransformable(c, > > available[i], sourceType)) { > > - List tail = > > getConversionPath(destinationType, available[i], > index + 1, allowNull); > > + List tail = > > getConversionPath(destinationType, available[i], > index + 1); > > if (tail != null) { > > tail.add(0, > available[i]); > > - return > tail; > > + if > (isPrecise(tail, sourceType, > > index)) { > > + > return tail; > > + } > > + > possibleResult = tail; > > } > > } > > } > > - return null; > > + return possibleResult; > > } > > > > + private boolean isPrecise(List > conversionPath, Class sourceType, > > int index) { > > + Transformer[] chain = getChain(); > > + Class currentSource = sourceType; > > + int i = 0; > > + for (Iterator iter = > conversionPath.iterator(); > > iter.hasNext(); i++) { > > + Class currentDest = > (Class) iter.next(); > > + if > (TransformerUtils.isImpreciseConversion(chain[index > > + i], currentDest, > > + > currentSource)) { > > + return false; > > + } > > + currentSource = > currentDest; > > + } > > + return true; > > + } > > + > > /** > > * Get the components array narrowed to a > Transformer[]. > > * @return Transformer[] > > Index: > src/core/net/sf/morph/transform/ImpreciseConverter.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/ImpreciseConverter.java > (revision > > 0) > > +++ > src/core/net/sf/morph/transform/ImpreciseConverter.java > (revision > > 0) > > @@ -0,0 +1,32 @@ > > +/* > > + * Copyright 2008 the original author or authors. > > + * > > + * 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 net.sf.morph.transform; > > + > > +/** > > + * Defines a converter whose operation may result > in a loss of data > > precision. > > + * > > + * @author mbenson > > + * @since Morph 1.0.2 > > + */ > > +public interface ImpreciseConverter extends > Converter { > > + /** > > + * Learn whether the specified conversion > might yield an imprecise > > result. > > + * @param destinationClass > > + * @param sourceClass > > + * @return boolean > > + */ > > + boolean isImpreciseConversion(Class > destinationClass, Class > > sourceClass); > > +} > > > > Property changes on: > > > src/core/net/sf/morph/transform/ImpreciseConverter.java > > > ___________________________________________________________________ > > Name: svn:eol-style > > + native > > > > Index: > > > src/core/net/sf/morph/transform/converters/ObjectToTextConverter.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/converters/ObjectToTextConverter.java > > (revision 362) > > +++ > src/core/net/sf/morph/transform/converters/ObjectToTextConverter.java > > (working copy) > > @@ -20,7 +20,9 @@ > > import net.sf.morph.Defaults; > > import net.sf.morph.transform.Converter; > > import net.sf.morph.transform.DecoratedConverter; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.transformers.BaseTransformer; > > +import net.sf.morph.util.TransformerUtils; > > > > /** > > * Converts an object to a textual representation > by calling the object's > > @@ -32,7 +34,7 @@ > > * @author Matt Sgarlata > > * @since Dec 24, 2004 > > */ > > -public class ObjectToTextConverter extends > BaseTransformer implements > > DecoratedConverter { > > +public class ObjectToTextConverter extends > BaseTransformer implements > > DecoratedConverter, ImpreciseConverter { > > > > private Converter textConverter; > > > > @@ -52,6 +54,13 @@ > > /** > > * {@inheritDoc} > > */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + return > TransformerUtils.isImpreciseConversion(getTextConverter(), > > destinationClass, String.class); > > + } > > + > > + /** > > + * {@inheritDoc} > > + */ > > protected boolean > isWrappingRuntimeExceptions() { > > return true; > > } > > Index: > > > src/core/net/sf/morph/transform/converters/TextToNumberConverter.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/converters/TextToNumberConverter.java > > (revision 361) > > +++ > src/core/net/sf/morph/transform/converters/TextToNumberConverter.java > > (working copy) > > @@ -32,7 +32,7 @@ > > import org.apache.commons.logging.LogFactory; > > > > /** > > - * Converts basic text types into primtive > numbers or {@link > > java.lang.Number} > > + * Converts basic text types into primitive > numbers or {@link > > java.lang.Number} > > * objects. > > * > > * @author Matt Sgarlata > > Index: > > > src/core/net/sf/morph/transform/converters/NumberToTextConverter.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/converters/NumberToTextConverter.java > > (revision 363) > > +++ > src/core/net/sf/morph/transform/converters/NumberToTextConverter.java > > (working copy) > > @@ -21,7 +21,9 @@ > > import net.sf.morph.Defaults; > > import net.sf.morph.transform.Converter; > > import net.sf.morph.transform.DecoratedConverter; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.transformers.BaseTransformer; > > +import net.sf.morph.util.TransformerUtils; > > > > /** > > * Converts {@link java.lang.Number}s into basic > text types ({@link > > java.lang.String}, > > @@ -30,7 +32,8 @@ > > * @author Matt Sgarlata > > * @since Jan 26, 2006 > > */ > > -public class NumberToTextConverter extends > BaseTransformer implements > > DecoratedConverter { > > +public class NumberToTextConverter extends > BaseTransformer implements > > DecoratedConverter, > > + ImpreciseConverter { > > > > private Converter textConverter; > > private Converter numberConverter; > > @@ -58,6 +61,13 @@ > > } > > > > /** > > + * {@inheritDoc} > > + */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + return > TransformerUtils.isImpreciseConversion(getTextConverter(), > > destinationClass, String.class); > > + } > > + > > + /** > > * Get the number converter used by this > NumberToTextConverter. > > * @return Converter > > */ > > Index: > src/core/net/sf/morph/transform/converters/TimeToTextConverter.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/converters/TimeToTextConverter.java > > (revision 360) > > +++ > src/core/net/sf/morph/transform/converters/TimeToTextConverter.java > > (working copy) > > @@ -22,7 +22,9 @@ > > import net.sf.morph.Defaults; > > import net.sf.morph.transform.Converter; > > import net.sf.morph.transform.DecoratedConverter; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.transformers.BaseTransformer; > > +import net.sf.morph.util.TransformerUtils; > > > > /** > > * Converts the basic time types ({@link > java.util.Date} and > > @@ -33,7 +35,8 @@ > > * @author Matt Sgarlata > > * @since Dec 31, 2004 > > */ > > -public class TimeToTextConverter extends > BaseTransformer implements > > DecoratedConverter { > > +public class TimeToTextConverter extends > BaseTransformer implements > > DecoratedConverter, > > + ImpreciseConverter { > > > > private DateFormat dateFormat; > > private Converter timeConverter; > > @@ -55,6 +58,13 @@ > > /** > > * {@inheritDoc} > > */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + return > TransformerUtils.isImpreciseConversion(getTextConverter(), > > destinationClass, String.class); > > + } > > + > > + /** > > + * {@inheritDoc} > > + */ > > protected boolean > isWrappingRuntimeExceptions() { > > return true; > > } > > Index: > src/core/net/sf/morph/transform/converters/TextConverter.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/converters/TextConverter.java > > (revision 357) > > +++ > src/core/net/sf/morph/transform/converters/TextConverter.java > > (working copy) > > @@ -22,6 +22,7 @@ > > > > import net.sf.morph.transform.DecoratedConverter; > > import > net.sf.morph.transform.ExplicitTransformer; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.TransformationException; > > import > net.sf.morph.transform.transformers.BaseTransformer; > > import net.sf.morph.util.ClassUtils; > > @@ -43,7 +44,7 @@ > > * @since Jan 2, 2005 > > */ > > public class TextConverter extends > BaseTransformer implements > > DecoratedConverter, > > - ExplicitTransformer { > > + ExplicitTransformer, > ImpreciseConverter { > > > > private static final Class CHAR_SEQUENCE = > > ClassUtils.isJdk14OrHigherPresent() ? ClassUtils > > > .convertToClass("java.lang.CharSequence") > > @@ -62,14 +63,7 @@ > > s.add(Character.class); > > s.add(char.class); > > s.add(null); > > - if (CHAR_SEQUENCE != null) { > > - s.add(CHAR_SEQUENCE); > > - try { > > - > CONSTRUCTOR_CACHE.put(CHAR_SEQUENCE, > > StringBuffer.class.getConstructor(new Class[] { > String.class })); > > - } catch (Exception e) { > > - //nope > > - } > > - } > > + s.add(CHAR_SEQUENCE); > > SOURCE_AND_DESTINATION_TYPES = > (Class[]) s.toArray(new > > Class[s.size()]); > > } > > > > @@ -106,7 +100,8 @@ > > } > > return new > Character(string.charAt(0)); > > } > > - if (destinationClass == > String.class) { > > + if (destinationClass == > String.class > > + || > (destinationClass == CHAR_SEQUENCE && > > CHAR_SEQUENCE != null)) { > > return string; > > } > > if (destinationClass == > byte[].class) { > > @@ -152,6 +147,16 @@ > > /** > > * {@inheritDoc} > > */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + if > (super.isImpreciseConversionImpl(destinationClass, > > sourceClass)) { > > + return true; > > + } > > + return isChar(destinationClass) && > !isChar(sourceClass); > > + } > > + > > + /** > > + * {@inheritDoc} > > + */ > > protected boolean > isAutomaticallyHandlingNulls() { > > return !isEmptyNull(); > > } > > Index: > > > src/core/net/sf/morph/transform/converters/BooleanToTextConverter.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/converters/BooleanToTextConverter.java > > (revision 362) > > +++ > src/core/net/sf/morph/transform/converters/BooleanToTextConverter.java > > (working copy) > > @@ -20,8 +20,10 @@ > > import net.sf.morph.Defaults; > > import net.sf.morph.transform.Converter; > > import net.sf.morph.transform.DecoratedConverter; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.TransformationException; > > import > net.sf.morph.transform.transformers.BaseTransformer; > > +import net.sf.morph.util.TransformerUtils; > > > > /** > > * Converts boolean values to text values. > Subclasses can build in > > support for > > @@ -32,10 +34,10 @@ > > * @author Matt Sgarlata > > * @since Jan 9, 2005 > > */ > > -public class BooleanToTextConverter extends > BaseTransformer implements > > DecoratedConverter { > > - > > +public class BooleanToTextConverter extends > BaseTransformer implements > > DecoratedConverter, ImpreciseConverter { > > + > > private static final Class[] SOURCE_TYPES = > { Boolean.class, > > boolean.class }; > > - > > + > > private Converter textConverter; > > > > /** > > @@ -93,9 +95,16 @@ > > /** > > * {@inheritDoc} > > */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + return > TransformerUtils.isImpreciseConversion(getTextConverter(), > > destinationClass, String.class); > > + } > > + > > + /** > > + * {@inheritDoc} > > + */ > > protected boolean > isWrappingRuntimeExceptions() { > > return true; > > - } > > + } > > > > /** > > * Get the text converter used by this > BaseToPrettyTextConverter. > > Index: > src/core/net/sf/morph/transform/converters/NumberConverter.java > > > =================================================================== > > --- > src/core/net/sf/morph/transform/converters/NumberConverter.java > > (revision 363) > > +++ > src/core/net/sf/morph/transform/converters/NumberConverter.java > > (working copy) > > @@ -19,6 +19,7 @@ > > import java.util.Locale; > > > > import net.sf.morph.transform.DecoratedConverter; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.TransformationException; > > import > net.sf.morph.transform.support.NumberRounder; > > import > net.sf.morph.transform.transformers.BaseTransformer; > > @@ -31,8 +32,8 @@ > > * @author Matt Sgarlata > > * @since Dec 14, 2004 > > */ > > -public class NumberConverter extends > BaseTransformer implements > > DecoratedConverter { > > - > > +public class NumberConverter extends > BaseTransformer implements > > DecoratedConverter, ImpreciseConverter { > > + > > private static final Class[] > SOURCE_AND_DESTINATION_TYPES = { > > Number.class, byte.class, > short.class, int.class, > > long.class, > > float.class, double.class, null > > @@ -116,9 +117,20 @@ > > /** > > * {@inheritDoc} > > */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + return > super.isImpreciseConversionImpl(destinationClass, > > sourceClass) > > + || > > > NumberUtils.NARROWNESS_COMPARATOR.compare(destinationClass, > > + > sourceClass) < 0; > > + } > > + > > + /** > > + * {@inheritDoc} > > + */ > > protected Object convertImpl(Class > destinationClass, Object source, > > Locale locale) throws Exception { > > - > > + if (destinationClass == null) { > > + return null; > > + } > > if (destinationClass.isPrimitive() > && source == null) { > > throw new > TransformationException(destinationClass, > > source); > > } > > Index: > > > src/core/net/sf/morph/transform/converters/BaseToPrettyTextConverter.java > > > =================================================================== > > --- > > > src/core/net/sf/morph/transform/converters/BaseToPrettyTextConverter.java > > (revision 362) > > +++ > > > src/core/net/sf/morph/transform/converters/BaseToPrettyTextConverter.java > > (working copy) > > @@ -18,7 +18,9 @@ > > import net.sf.morph.Defaults; > > import net.sf.morph.transform.Converter; > > import net.sf.morph.transform.DecoratedConverter; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.transformers.BaseReflectorTransformer; > > +import net.sf.morph.util.TransformerUtils; > > > > /** > > * Base class for converts that convert objects to > a pretty > > programmer-friendly > > @@ -27,7 +29,8 @@ > > * @author Matt Sgarlata > > * @since Feb 15, 2005 > > */ > > -public abstract class BaseToPrettyTextConverter > extends > > BaseReflectorTransformer implements > DecoratedConverter { > > +public abstract class BaseToPrettyTextConverter > extends > > BaseReflectorTransformer > > + implements DecoratedConverter, > ImpreciseConverter { > > > > private String prefix; > > private String suffix; > > @@ -161,4 +164,19 @@ > > public void setShowNullValues(boolean > showNullValues) { > > this.showNullValues = > showNullValues; > > } > > + > > + /** > > + * {@inheritDoc} > > + */ > > + protected boolean > isImpreciseConversionImpl(Class > > destinationClass, Class sourceClass) { > > + return > TransformerUtils.isImpreciseConversion(getTextConverter(), > > destinationClass, sourceClass); > > + } > > + > > + /** > > + * Get the intermediate class passed to > the text converter. > > + * @return > > + */ > > + protected Class getIntermediateClass() { > > + return StringBuffer.class; > > + } > > } > > Index: src/core/net/sf/morph/util/NumberUtils.java > > > =================================================================== > > --- src/core/net/sf/morph/util/NumberUtils.java > (revision 365) > > +++ src/core/net/sf/morph/util/NumberUtils.java > (working copy) > > @@ -19,6 +19,7 @@ > > import java.lang.reflect.Method; > > import java.math.BigDecimal; > > import java.math.BigInteger; > > +import java.util.Comparator; > > import java.util.HashMap; > > import java.util.HashSet; > > import java.util.Iterator; > > @@ -69,6 +70,31 @@ > > } > > } > > > > + private static class NarrownessComparator > implements Comparator { > > + /** > > + * {@inheritDoc} > > + */ > > + public int compare(Object arg0, > Object arg1) { > > + if (arg0 == arg1) { > > + return 0; > > + } > > + Class c0 = getType(arg0); > > + Class c1 = getType(arg1); > > + if (c0 == c1 || c0 == null > || c1 == null) { > > + return 0; > > + } > > + return > > > getMaximumForType(c0).compareTo(getMaximumForType(c1)); > > + } > > + > > + private Class getType(Object o) { > > + if > (MAXIMUMS_FOR_TYPES.containsKey(o)) { > > + return (Class) o; > > + } > > + Class test = > ClassUtils.getClass(o); > > + return > MAXIMUMS_FOR_TYPES.containsKey(test) ? test > > : null; > > + } > > + } > > + > > /** > > * A Map of BigDecimals keyed by Class that > indicate the maximum > > value that > > * the given (Number) Class may taken on. > > @@ -80,11 +106,16 @@ > > * the given (Number) Class may taken on. > > */ > > public static final Map MINIMUMS_FOR_TYPES; > > - > > - public static final Map > WRAPPERS_FOR_PRIMITIVE_TYPES; > > > > - public static final Map NUMBER_FACTORIES; > > + /** > > + * Comparator of class/object type > narrowness. > > + */ > > + public static final Comparator > NARROWNESS_COMPARATOR = new > > NarrownessComparator(); > > > > + private static final Map > WRAPPERS_FOR_PRIMITIVE_TYPES; > > + > > + private static final Map NUMBER_FACTORIES; > > + > > /** > > * Used by {@link > NumberUtils#isNumber(Class)}. > > */ > > Index: > src/core/net/sf/morph/util/TransformerUtils.java > > > =================================================================== > > --- > src/core/net/sf/morph/util/TransformerUtils.java > (revision 357) > > +++ > src/core/net/sf/morph/util/TransformerUtils.java > (working copy) > > @@ -1,5 +1,5 @@ > > /* > > - * Copyright 2004-2005, 2007 the original author > or authors. > > + * Copyright 2004-2005, 2007-2008 the original > author or authors. > > * > > * 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 > > @@ -26,6 +26,7 @@ > > import net.sf.morph.transform.Converter; > > import net.sf.morph.transform.Copier; > > import > net.sf.morph.transform.ExplicitTransformer; > > +import net.sf.morph.transform.ImpreciseConverter; > > import > net.sf.morph.transform.TransformationException; > > import net.sf.morph.transform.Transformer; > > > > @@ -90,6 +91,24 @@ > > } > > > > /** > > + * Learn whether > <code>transformer</code>'s conversion > > + * of <code>sourceClass</code> to > <code>destinationClass</code> > > might yield an imprecise result. > > + * @param transformer > > + * @param destinationClass > > + * @param sourceClass > > + * @return boolean > > + * @see ImpreciseConverter > > + */ > > + public static boolean > isImpreciseConversion(Transformer > > transformer, > > + Class destinationClass, > Class sourceClass) { > > + if (transformer instanceof > ImpreciseConverter) { > > + return > ((ImpreciseConverter) > > transformer).isImpreciseConversion( > > + > destinationClass, sourceClass); > > + } > > + return destinationClass == null && > sourceClass != null; > > + } > > + > > + /** > > * Performs a transformation of one object > graph into another > > object graph. > > * > > * @param destinationType > > > > > ------------------------------------------------------------------------- > > This SF.net email is sponsored by: Microsoft > > Defy all challenges. Microsoft(R) Visual Studio > 2005. > > > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ > > _______________________________________________ > > morph-developer mailing list > > mor...@li... > > > https://lists.sourceforge.net/lists/listinfo/morph-developer > > > > > > > -- > This message is intended only for the named > recipient. If you are not the > intended recipient, you are notified that > disclosing, copying, distributing, > or taking any action in reliance on the contents of > this information is > strictly prohibited. > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Microsoft > Defy all challenges. Microsoft(R) Visual Studio > 2005. > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/> _______________________________________________ > morph-developer mailing list > mor...@li... > https://lists.sourceforge.net/lists/listinfo/morph-developer > ____________________________________________________________________________________ Looking for last minute shopping deals? Find them fast with Yahoo! Search. http://tools.search.yahoo.com/newsearch/category.php?category=shopping |
From: Matt S. <mat...@sp...> - 2008-01-07 15:47:16
|
I have been thinking more about this approach, and it's really starting to grow on me. I do have one concern though, can this approach be extended to Copiers? For example, a Map -> Object copy could probably be considered an imprecise transformation because the Map may have more keys than the Object has properties. In addition to your approach, I also like the idea of cleaning up the internal implementation in Morph so that ordering of source and destination classes is preserved for the following reasons: 1) for at least some portion of users, setting the order of source and destination classes will make sense as an indication of the transformer's preferences for performing transformations (so for this class of users, creating new transformers that play nicely with the ChainedTransformerTestCase will be simpler) 2) I think a general change from using HashSets to ordered sets in Morph's implementation will mean transformations happen more consistently across JVMs and across time on the same JVM, leading to a more stable platform So, what I did is I basically went through the Morph codebase and replaced HashSets with ordered sets (preference order is: JDK 1.4 LinkedHashSet, Commons-collections ListOrderedSet, copy of ListOrderedSet in net.sf.morph.util). I was never able to modify the ChainedTransformerTestCase so that it consistently threw an error. However, after working on the test case long enough, eventually something changed in my environment so that the test started to fail. I did my change of HashSets to ordered sets, and that was able to fix the broken test. I checked in my changes for you to take a look at... Matt S On Jan 6, 2008 12:59 PM, Matt Benson <gud...@ya...> wrote: > Here's what I've got. > > -Matt B > > > > ____________________________________________________________________________________ > Be a better friend, newshound, and > know-it-all with Yahoo! Mobile. Try it now. > http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ > > Index: > src/core/net/sf/morph/transform/transformers/SimpleDelegatingTransformer.java > =================================================================== > --- > src/core/net/sf/morph/transform/transformers/SimpleDelegatingTransformer.java > (revision 357) > +++ > src/core/net/sf/morph/transform/transformers/SimpleDelegatingTransformer.java > (working copy) > @@ -1,5 +1,5 @@ > /* > - * Copyright 2004-2005, 2007 the original author or authors. > + * Copyright 2004-2005, 2007-2008 the original author or authors. > * > * 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 > @@ -35,6 +35,7 @@ > import net.sf.morph.transform.DecoratedConverter; > import net.sf.morph.transform.DecoratedCopier; > import net.sf.morph.transform.ExplicitTransformer; > +import net.sf.morph.transform.ImpreciseConverter; > import net.sf.morph.transform.NodeCopier; > import net.sf.morph.transform.TransformationException; > import net.sf.morph.transform.Transformer; > @@ -93,11 +94,11 @@ > * @since Dec 12, 2004 > */ > public class SimpleDelegatingTransformer extends BaseCompositeTransformer > implements > - SpecializableComposite, ExplicitTransformer, Transformer, > DecoratedCopier, DecoratedConverter, Cloneable { > + SpecializableComposite, ExplicitTransformer, Transformer, > DecoratedCopier, > + DecoratedConverter, Cloneable, ImpreciseConverter { > > //TODO extract BaseDelegatingTransformer with pluggable delegate > selection > > - > private static class MapThreadLocal extends ThreadLocal { > protected Object initialValue() { > return new HashMap(); > @@ -138,6 +139,7 @@ > } > > private Specializer specializer; > + private boolean preferPreciseTransformers; > > private transient ThreadLocal > visitedSourceToDestinationMapThreadLocal = new MapThreadLocal(); > private transient ThreadLocal stackDepthThreadLocal = new > StackDepthThreadLocal(); > @@ -225,6 +227,14 @@ > > /** > * {@inheritDoc} > + */ > + protected boolean isImpreciseConversionImpl(Class > destinationClass, Class sourceClass) { > + return TransformerUtils.isImpreciseConversion > (getTransformer(destinationClass, > + sourceClass), destinationClass, > sourceClass); > + } > + > + /** > + * {@inheritDoc} > * @see > net.sf.morph.transform.transformers.BaseTransformer#getSourceClassesImpl() > */ > protected Class[] getSourceClassesImpl() throws Exception { > @@ -477,6 +487,7 @@ > * if no suitable transformer could be found > */ > private Transformer getTransformer(Class transformerType, Class > destinationClass, Class sourceClass) throws TransformationException { > + Transformer candidate = null; > for (int i = 0; i < components.length; i++) { > // if the transformer is the correct type > Transformer transformer = (Transformer) > components[i]; > @@ -484,6 +495,13 @@ > // if the transformer is capable of > performing the transformation > if (TransformerUtils.isTransformable( > transformer, > destinationClass, sourceClass)) { > + if (isPreferPreciseTransformers() > + && candidate == > null > + && > TransformerUtils.isImpreciseConversion(transformer, > + > destinationClass, sourceClass)) { > + candidate = transformer; > + continue; > + } > if (getLog().isTraceEnabled()) { > getLog().trace("Using " > + > ClassUtils.getUnqualifiedClassName(transformerType) > @@ -496,7 +514,9 @@ > return transformer; > } > } > - > + if (candidate != null) { > + return candidate; > + } > } > throw new TransformationException( > "Could not find a transformer that can transform > objects of " > @@ -612,4 +632,20 @@ > source); > } > > + /** > + * Get the preferPreciseTransformers. > + * @return boolean > + */ > + public boolean isPreferPreciseTransformers() { > + return preferPreciseTransformers; > + } > + > + /** > + * Set the preferPreciseTransformers. Default false. > + * @param preferPreciseTransformers the boolean to set > + */ > + public void setPreferPreciseTransformers(boolean > preferPreciseTransformers) { > + this.preferPreciseTransformers = > preferPreciseTransformers; > + } > + > } > \ No newline at end of file > Index: src/core/net/sf/morph/transform/transformers/BaseTransformer.java > =================================================================== > --- src/core/net/sf/morph/transform/transformers/BaseTransformer.java > (revision 358) > +++ src/core/net/sf/morph/transform/transformers/BaseTransformer.java > (working copy) > @@ -570,6 +570,35 @@ > } > } > > + /** > + * Implementation of isImpreciseConversion > + * @param destinationClass > + * @param sourceClass > + * @return > + */ > + protected boolean isImpreciseConversionImpl(Class > destinationClass, Class sourceClass) { > + return destinationClass == null && sourceClass != null; > + } > + > + /** > + * Learn whether the specified conversion yields an imprecise > result. > + * @param destinationClass > + * @param sourceClass > + * @return boolean > + */ > + public final boolean isImpreciseConversion(Class destinationClass, > Class sourceClass) { > + try { > + return isImpreciseConversionImpl(destinationClass, > sourceClass); > + } catch (Exception e) { > + if (e instanceof RuntimeException && > !isWrappingRuntimeExceptions()) { > + throw (RuntimeException) e; > + } > + throw new TransformationException("Could not > determine if conversion of " > + + sourceClass + " to " + > destinationClass > + + " results in a loss of > precision", e); > + } > + } > + > // property getters and setters > > /** > Index: > src/core/net/sf/morph/transform/transformers/ChainedTransformer.java > =================================================================== > --- src/core/net/sf/morph/transform/transformers/ChainedTransformer.java > (revision 357) > +++ src/core/net/sf/morph/transform/transformers/ChainedTransformer.java > (working copy) > @@ -1,5 +1,5 @@ > /* > - * Copyright 2004-2005, 2007 the original author or authors. > + * Copyright 2004-2005, 2007-2008 the original author or authors. > * > * 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 > @@ -16,6 +16,7 @@ > package net.sf.morph.transform.transformers; > > import java.util.ArrayList; > +import java.util.Iterator; > import java.util.List; > import java.util.Locale; > > @@ -25,6 +26,7 @@ > import net.sf.morph.transform.DecoratedConverter; > import net.sf.morph.transform.DecoratedCopier; > import net.sf.morph.transform.ExplicitTransformer; > +import net.sf.morph.transform.ImpreciseConverter; > import net.sf.morph.transform.TransformationException; > import net.sf.morph.transform.Transformer; > import net.sf.morph.transform.copiers.CopierDecorator; > @@ -40,7 +42,7 @@ > * @since Nov 24, 2004 > */ > public class ChainedTransformer extends BaseCompositeTransformer > implements > - DecoratedConverter, DecoratedCopier, ExplicitTransformer { > + DecoratedConverter, DecoratedCopier, ExplicitTransformer, > ImpreciseConverter { > > private Converter copyConverter; > > @@ -67,6 +69,14 @@ > } > > /** > + * {@inheritDoc} > + */ > + protected boolean isImpreciseConversionImpl(Class > destinationClass, Class sourceClass) { > + List conversionPath = getConversionPath(destinationClass, > sourceClass); > + return !isPrecise(conversionPath, sourceClass, 0); > + } > + > + /** > * Get the converter used when using a ChainedTransformer as a > Copier. > * @return > */ > @@ -113,6 +123,7 @@ > throw new TransformationException(destinationClass, > sourceType, null, > "Chained conversion path could not > be determined"); > } > + log.debug("Using chained conversion path " + > conversionPath); > Object o = source; > for (int i = 0; i < conversionPath.size(); i++) { > o = getConverter(chain[i]).convert((Class) > conversionPath.get(i), o, locale); > @@ -144,6 +155,7 @@ > throw new TransformationException(destinationClass, > source, null, > "Chained conversion path could not > be determined"); > } > + log.debug("Using chained conversion path " + > conversionPath); > Object last = getCopyConverter().convert((Class) > conversionPath.get(chain.length - 2), source, locale); > ((Copier) copier).copy(destination, last, locale); > } > @@ -192,13 +204,7 @@ > * @return List > */ > protected List getConversionPath(Class destinationType, Class > sourceType) { > - if (sourceType != null) { > - List withoutNull = > getConversionPath(destinationType, sourceType, 0, false); > - if (withoutNull != null) { > - return withoutNull; > - } > - } > - return getConversionPath(destinationType, sourceType, 0, > true); > + return getConversionPath(destinationType, sourceType, 0); > } > > /** > @@ -210,7 +216,7 @@ > * @param allowNull > * @return List > */ > - private List getConversionPath(Class destinationType, Class > sourceType, int index, boolean allowNull) { > + private List getConversionPath(Class destinationType, Class > sourceType, int index) { > Transformer[] chain = getChain(); > Transformer c = chain[index]; > if (index + 1 == chain.length) { > @@ -221,22 +227,38 @@ > } > return null; > } > + List possibleResult = null; > Class[] available = c.getDestinationClasses(); > for (int i = 0; i < available.length; i++) { > - if (available[i] == null && !allowNull) { > - continue; > - } > if (TransformerUtils.isTransformable(c, > available[i], sourceType)) { > - List tail = > getConversionPath(destinationType, available[i], index + 1, allowNull); > + List tail = > getConversionPath(destinationType, available[i], index + 1); > if (tail != null) { > tail.add(0, available[i]); > - return tail; > + if (isPrecise(tail, sourceType, > index)) { > + return tail; > + } > + possibleResult = tail; > } > } > } > - return null; > + return possibleResult; > } > > + private boolean isPrecise(List conversionPath, Class sourceType, > int index) { > + Transformer[] chain = getChain(); > + Class currentSource = sourceType; > + int i = 0; > + for (Iterator iter = conversionPath.iterator(); > iter.hasNext(); i++) { > + Class currentDest = (Class) iter.next(); > + if (TransformerUtils.isImpreciseConversion(chain[index > + i], currentDest, > + currentSource)) { > + return false; > + } > + currentSource = currentDest; > + } > + return true; > + } > + > /** > * Get the components array narrowed to a Transformer[]. > * @return Transformer[] > Index: src/core/net/sf/morph/transform/ImpreciseConverter.java > =================================================================== > --- src/core/net/sf/morph/transform/ImpreciseConverter.java (revision > 0) > +++ src/core/net/sf/morph/transform/ImpreciseConverter.java (revision > 0) > @@ -0,0 +1,32 @@ > +/* > + * Copyright 2008 the original author or authors. > + * > + * 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 net.sf.morph.transform; > + > +/** > + * Defines a converter whose operation may result in a loss of data > precision. > + * > + * @author mbenson > + * @since Morph 1.0.2 > + */ > +public interface ImpreciseConverter extends Converter { > + /** > + * Learn whether the specified conversion might yield an imprecise > result. > + * @param destinationClass > + * @param sourceClass > + * @return boolean > + */ > + boolean isImpreciseConversion(Class destinationClass, Class > sourceClass); > +} > > Property changes on: > src/core/net/sf/morph/transform/ImpreciseConverter.java > ___________________________________________________________________ > Name: svn:eol-style > + native > > Index: > src/core/net/sf/morph/transform/converters/ObjectToTextConverter.java > =================================================================== > --- src/core/net/sf/morph/transform/converters/ObjectToTextConverter.java > (revision 362) > +++ src/core/net/sf/morph/transform/converters/ObjectToTextConverter.java > (working copy) > @@ -20,7 +20,9 @@ > import net.sf.morph.Defaults; > import net.sf.morph.transform.Converter; > import net.sf.morph.transform.DecoratedConverter; > +import net.sf.morph.transform.ImpreciseConverter; > import net.sf.morph.transform.transformers.BaseTransformer; > +import net.sf.morph.util.TransformerUtils; > > /** > * Converts an object to a textual representation by calling the object's > @@ -32,7 +34,7 @@ > * @author Matt Sgarlata > * @since Dec 24, 2004 > */ > -public class ObjectToTextConverter extends BaseTransformer implements > DecoratedConverter { > +public class ObjectToTextConverter extends BaseTransformer implements > DecoratedConverter, ImpreciseConverter { > > private Converter textConverter; > > @@ -52,6 +54,13 @@ > /** > * {@inheritDoc} > */ > + protected boolean isImpreciseConversionImpl(Class > destinationClass, Class sourceClass) { > + return TransformerUtils.isImpreciseConversion(getTextConverter(), > destinationClass, String.class); > + } > + > + /** > + * {@inheritDoc} > + */ > protected boolean isWrappingRuntimeExceptions() { > return true; > } > Index: > src/core/net/sf/morph/transform/converters/TextToNumberConverter.java > =================================================================== > --- src/core/net/sf/morph/transform/converters/TextToNumberConverter.java > (revision 361) > +++ src/core/net/sf/morph/transform/converters/TextToNumberConverter.java > (working copy) > @@ -32,7 +32,7 @@ > import org.apache.commons.logging.LogFactory; > > /** > - * Converts basic text types into primtive numbers or {@link > java.lang.Number} > + * Converts basic text types into primitive numbers or {@link > java.lang.Number} > * objects. > * > * @author Matt Sgarlata > Index: > src/core/net/sf/morph/transform/converters/NumberToTextConverter.java > =================================================================== > --- src/core/net/sf/morph/transform/converters/NumberToTextConverter.java > (revision 363) > +++ src/core/net/sf/morph/transform/converters/NumberToTextConverter.java > (working copy) > @@ -21,7 +21,9 @@ > import net.sf.morph.Defaults; > import net.sf.morph.transform.Converter; > import net.sf.morph.transform.DecoratedConverter; > +import net.sf.morph.transform.ImpreciseConverter; > import net.sf.morph.transform.transformers.BaseTransformer; > +import net.sf.morph.util.TransformerUtils; > > /** > * Converts {@link java.lang.Number}s into basic text types ({@link > java.lang.String}, > @@ -30,7 +32,8 @@ > * @author Matt Sgarlata > * @since Jan 26, 2006 > */ > -public class NumberToTextConverter extends BaseTransformer implements > DecoratedConverter { > +public class NumberToTextConverter extends BaseTransformer implements > DecoratedConverter, > + ImpreciseConverter { > > private Converter textConverter; > private Converter numberConverter; > @@ -58,6 +61,13 @@ > } > > /** > + * {@inheritDoc} > + */ > + protected boolean isImpreciseConversionImpl(Class > destinationClass, Class sourceClass) { > + return TransformerUtils.isImpreciseConversion(getTextConverter(), > destinationClass, String.class); > + } > + > + /** > * Get the number converter used by this NumberToTextConverter. > * @return Converter > */ > Index: src/core/net/sf/morph/transform/converters/TimeToTextConverter.java > =================================================================== > --- src/core/net/sf/morph/transform/converters/TimeToTextConverter.java > (revision 360) > +++ src/core/net/sf/morph/transform/converters/TimeToTextConverter.java > (working copy) > @@ -22,7 +22,9 @@ > import net.sf.morph.Defaults; > import net.sf.morph.transform.Converter; > import net.sf.morph.transform.DecoratedConverter; > +import net.sf.morph.transform.ImpreciseConverter; > import net.sf.morph.transform.transformers.BaseTransformer; > +import net.sf.morph.util.TransformerUtils; > > /** > * Converts the basic time types ({@link java.util.Date} and > @@ -33,7 +35,8 @@ > * @author Matt Sgarlata > * @since Dec 31, 2004 > */ > -public class TimeToTextConverter extends BaseTransformer implements > DecoratedConverter { > +public class TimeToTextConverter extends BaseTransformer implements > DecoratedConverter, > + ImpreciseConverter { > > private DateFormat dateFormat; > private Converter timeConverter; > @@ -55,6 +58,13 @@ > /** > * {@inheritDoc} > */ > + protected boolean isImpreciseConversionImpl(Class > destinationClass, Class sourceClass) { > + return TransformerUtils.isImpreciseConversion(getTextConverter(), > destinationClass, String.class); > + } > + > + /** > + * {@inheritDoc} > + */ > protected boolean isWrappingRuntimeExceptions() { > return true; > } > Index: src/core/net/sf/morph/transform/converters/TextConverter.java > =================================================================== > --- src/core/net/sf/morph/transform/converters/TextConverter.java > (revision 357) > +++ src/core/net/sf/morph/transform/converters/TextConverter.java > (working copy) > @@ -22,6 +22,7 @@ > > import net.sf.morph.transform.DecoratedConverter; > import net.sf.morph.transform.ExplicitTransformer; > +import net.sf.morph.transform.ImpreciseConverter; > import net.sf.morph.transform.TransformationException; > import net.sf.morph.transform.transformers.BaseTransformer; > import net.sf.morph.util.ClassUtils; > @@ -43,7 +44,7 @@ > * @since Jan 2, 2005 > */ > public class TextConverter extends BaseTransformer implements > DecoratedConverter, > - ExplicitTransformer { > + ExplicitTransformer, ImpreciseConverter { > > private static final Class CHAR_SEQUENCE = > ClassUtils.isJdk14OrHigherPresent() ? ClassUtils > .convertToClass("java.lang.CharSequence") > @@ -62,14 +63,7 @@ > s.add(Character.class); > s.add(char.class); > s.add(null); > - if (CHAR_SEQUENCE != null) { > - s.add(CHAR_SEQUENCE); > - try { > - CONSTRUCTOR_CACHE.put(CHAR_SEQUENCE, > StringBuffer.class.getConstructor(new Class[] { String.class })); > - } catch (Exception e) { > - //nope > - } > - } > + s.add(CHAR_SEQUENCE); > SOURCE_AND_DESTINATION_TYPES = (Class[]) s.toArray(new > Class[s.size()]); > } > > @@ -106,7 +100,8 @@ > } > return new Character(string.charAt(0)); > } > - if (destinationClass == String.class) { > + if (destinationClass == String.class > + || (destinationClass == CHAR_SEQUENCE && > CHAR_SEQUENCE != null)) { > return string; > } > if (destinationClass == byte[].class) { > @@ -152,6 +147,16 @@ > /** > * {@inheritDoc} > */ > + protected boolean isImpreciseConversionImpl(Class > destinationClass, Class sourceClass) { > + if (super.isImpreciseConversionImpl(destinationClass, > sourceClass)) { > + return true; > + } > + return isChar(destinationClass) && !isChar(sourceClass); > + } > + > + /** > + * {@inheritDoc} > + */ > protected boolean isAutomaticallyHandlingNulls() { > return !isEmptyNull(); > } > Index: > src/core/net/sf/morph/transform/converters/BooleanToTextConverter.java > =================================================================== > --- src/core/net/sf/morph/transform/converters/BooleanToTextConverter.java > (revision 362) > +++ src/core/net/sf/morph/transform/converters/BooleanToTextConverter.java > (working copy) > @@ -20,8 +20,10 @@ > import net.sf.morph.Defaults; > import net.sf.morph.transform.Converter; > import net.sf.morph.transform.DecoratedConverter; > +import net.sf.morph.transform.ImpreciseConverter; > import net.sf.morph.transform.TransformationException; > import net.sf.morph.transform.transformers.BaseTransformer; > +import net.sf.morph.util.TransformerUtils; > > /** > * Converts boolean values to text values. Subclasses can build in > support for > @@ -32,10 +34,10 @@ > * @author Matt Sgarlata > * @since Jan 9, 2005 > */ > -public class BooleanToTextConverter extends BaseTransformer implements > DecoratedConverter { > - > +public class BooleanToTextConverter extends BaseTransformer implements > DecoratedConverter, ImpreciseConverter { > + > private static final Class[] SOURCE_TYPES = { Boolean.class, > boolean.class }; > - > + > private Converter textConverter; > > /** > @@ -93,9 +95,16 @@ > /** > * {@inheritDoc} > */ > + protected boolean isImpreciseConversionImpl(Class > destinationClass, Class sourceClass) { > + return TransformerUtils.isImpreciseConversion(getTextConverter(), > destinationClass, String.class); > + } > + > + /** > + * {@inheritDoc} > + */ > protected boolean isWrappingRuntimeExceptions() { > return true; > - } > + } > > /** > * Get the text converter used by this BaseToPrettyTextConverter. > Index: src/core/net/sf/morph/transform/converters/NumberConverter.java > =================================================================== > --- src/core/net/sf/morph/transform/converters/NumberConverter.java > (revision 363) > +++ src/core/net/sf/morph/transform/converters/NumberConverter.java > (working copy) > @@ -19,6 +19,7 @@ > import java.util.Locale; > > import net.sf.morph.transform.DecoratedConverter; > +import net.sf.morph.transform.ImpreciseConverter; > import net.sf.morph.transform.TransformationException; > import net.sf.morph.transform.support.NumberRounder; > import net.sf.morph.transform.transformers.BaseTransformer; > @@ -31,8 +32,8 @@ > * @author Matt Sgarlata > * @since Dec 14, 2004 > */ > -public class NumberConverter extends BaseTransformer implements > DecoratedConverter { > - > +public class NumberConverter extends BaseTransformer implements > DecoratedConverter, ImpreciseConverter { > + > private static final Class[] SOURCE_AND_DESTINATION_TYPES = { > Number.class, byte.class, short.class, int.class, > long.class, > float.class, double.class, null > @@ -116,9 +117,20 @@ > /** > * {@inheritDoc} > */ > + protected boolean isImpreciseConversionImpl(Class > destinationClass, Class sourceClass) { > + return super.isImpreciseConversionImpl(destinationClass, > sourceClass) > + || > NumberUtils.NARROWNESS_COMPARATOR.compare(destinationClass, > + sourceClass) < 0; > + } > + > + /** > + * {@inheritDoc} > + */ > protected Object convertImpl(Class destinationClass, Object source, > Locale locale) throws Exception { > - > + if (destinationClass == null) { > + return null; > + } > if (destinationClass.isPrimitive() && source == null) { > throw new TransformationException(destinationClass, > source); > } > Index: > src/core/net/sf/morph/transform/converters/BaseToPrettyTextConverter.java > =================================================================== > --- > src/core/net/sf/morph/transform/converters/BaseToPrettyTextConverter.java > (revision 362) > +++ > src/core/net/sf/morph/transform/converters/BaseToPrettyTextConverter.java > (working copy) > @@ -18,7 +18,9 @@ > import net.sf.morph.Defaults; > import net.sf.morph.transform.Converter; > import net.sf.morph.transform.DecoratedConverter; > +import net.sf.morph.transform.ImpreciseConverter; > import net.sf.morph.transform.transformers.BaseReflectorTransformer; > +import net.sf.morph.util.TransformerUtils; > > /** > * Base class for converts that convert objects to a pretty > programmer-friendly > @@ -27,7 +29,8 @@ > * @author Matt Sgarlata > * @since Feb 15, 2005 > */ > -public abstract class BaseToPrettyTextConverter extends > BaseReflectorTransformer implements DecoratedConverter { > +public abstract class BaseToPrettyTextConverter extends > BaseReflectorTransformer > + implements DecoratedConverter, ImpreciseConverter { > > private String prefix; > private String suffix; > @@ -161,4 +164,19 @@ > public void setShowNullValues(boolean showNullValues) { > this.showNullValues = showNullValues; > } > + > + /** > + * {@inheritDoc} > + */ > + protected boolean isImpreciseConversionImpl(Class > destinationClass, Class sourceClass) { > + return TransformerUtils.isImpreciseConversion(getTextConverter(), > destinationClass, sourceClass); > + } > + > + /** > + * Get the intermediate class passed to the text converter. > + * @return > + */ > + protected Class getIntermediateClass() { > + return StringBuffer.class; > + } > } > Index: src/core/net/sf/morph/util/NumberUtils.java > =================================================================== > --- src/core/net/sf/morph/util/NumberUtils.java (revision 365) > +++ src/core/net/sf/morph/util/NumberUtils.java (working copy) > @@ -19,6 +19,7 @@ > import java.lang.reflect.Method; > import java.math.BigDecimal; > import java.math.BigInteger; > +import java.util.Comparator; > import java.util.HashMap; > import java.util.HashSet; > import java.util.Iterator; > @@ -69,6 +70,31 @@ > } > } > > + private static class NarrownessComparator implements Comparator { > + /** > + * {@inheritDoc} > + */ > + public int compare(Object arg0, Object arg1) { > + if (arg0 == arg1) { > + return 0; > + } > + Class c0 = getType(arg0); > + Class c1 = getType(arg1); > + if (c0 == c1 || c0 == null || c1 == null) { > + return 0; > + } > + return > getMaximumForType(c0).compareTo(getMaximumForType(c1)); > + } > + > + private Class getType(Object o) { > + if (MAXIMUMS_FOR_TYPES.containsKey(o)) { > + return (Class) o; > + } > + Class test = ClassUtils.getClass(o); > + return MAXIMUMS_FOR_TYPES.containsKey(test) ? test > : null; > + } > + } > + > /** > * A Map of BigDecimals keyed by Class that indicate the maximum > value that > * the given (Number) Class may taken on. > @@ -80,11 +106,16 @@ > * the given (Number) Class may taken on. > */ > public static final Map MINIMUMS_FOR_TYPES; > - > - public static final Map WRAPPERS_FOR_PRIMITIVE_TYPES; > > - public static final Map NUMBER_FACTORIES; > + /** > + * Comparator of class/object type narrowness. > + */ > + public static final Comparator NARROWNESS_COMPARATOR = new > NarrownessComparator(); > > + private static final Map WRAPPERS_FOR_PRIMITIVE_TYPES; > + > + private static final Map NUMBER_FACTORIES; > + > /** > * Used by {@link NumberUtils#isNumber(Class)}. > */ > Index: src/core/net/sf/morph/util/TransformerUtils.java > =================================================================== > --- src/core/net/sf/morph/util/TransformerUtils.java (revision 357) > +++ src/core/net/sf/morph/util/TransformerUtils.java (working copy) > @@ -1,5 +1,5 @@ > /* > - * Copyright 2004-2005, 2007 the original author or authors. > + * Copyright 2004-2005, 2007-2008 the original author or authors. > * > * 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 > @@ -26,6 +26,7 @@ > import net.sf.morph.transform.Converter; > import net.sf.morph.transform.Copier; > import net.sf.morph.transform.ExplicitTransformer; > +import net.sf.morph.transform.ImpreciseConverter; > import net.sf.morph.transform.TransformationException; > import net.sf.morph.transform.Transformer; > > @@ -90,6 +91,24 @@ > } > > /** > + * Learn whether <code>transformer</code>'s conversion > + * of <code>sourceClass</code> to <code>destinationClass</code> > might yield an imprecise result. > + * @param transformer > + * @param destinationClass > + * @param sourceClass > + * @return boolean > + * @see ImpreciseConverter > + */ > + public static boolean isImpreciseConversion(Transformer > transformer, > + Class destinationClass, Class sourceClass) { > + if (transformer instanceof ImpreciseConverter) { > + return ((ImpreciseConverter) > transformer).isImpreciseConversion( > + destinationClass, sourceClass); > + } > + return destinationClass == null && sourceClass != null; > + } > + > + /** > * Performs a transformation of one object graph into another > object graph. > * > * @param destinationType > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Microsoft > Defy all challenges. Microsoft(R) Visual Studio 2005. > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ > _______________________________________________ > morph-developer mailing list > mor...@li... > https://lists.sourceforge.net/lists/listinfo/morph-developer > > -- This message is intended only for the named recipient. If you are not the intended recipient, you are notified that disclosing, copying, distributing, or taking any action in reliance on the contents of this information is strictly prohibited. |
From: Matt B. <gud...@ya...> - 2008-01-06 17:59:45
|
Here's what I've got. -Matt B ____________________________________________________________________________________ Be a better friend, newshound, and know-it-all with Yahoo! Mobile. Try it now. http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ |
From: Matt B. <gud...@ya...> - 2008-01-04 21:04:54
|
In the meantime I am experimenting with the ImpreciseConverter idea. When I get things working satisfactorily I'll post a patch. Let me remind you that it would be fairly unintrusive since ChainedTransformer would be the only internal Morph code that would need the information. Users might like to have such information available; another example of imprecise conversions is numeric conversions, e.g. long to int, int to byte, etc. -Matt B --- Matt Sgarlata <mat...@sp...> wrote: > It sounds to me like I need to fix how the source > and destination arrays are > constructed so that order is preserved. > > I agree it is definitely not OK for this to require > repetitive configuration > to prevent difficult to detect errors. > > I will take a look first thing Monday. > > Matt > > On Jan 4, 2008 1:04 PM, Matt Benson > <gud...@ya...> wrote: > > > Basically the order of destination classes in a > given > > converter in the chain already does influence the > > conversion path chosen. However, many of the > stock > > transformers use sets to build the source and/or > > destination class arrays, so the final order is > > unpredictable. As for examples, anytime you > convert a > > string to a char/Character, you (unless the string > is > > exactly one character in length) lose information. > > Anytime you convert an object to null, you lose > all > > information that was associated with that object. > So > > if you, as in ChainedTransformerTest, chain a > > TextToNumberConverter, a DefaultToTextConverter, > and > > another TextToNumberConverter, and the > > DefaultToTextConverter happens to return a char > type > > before one of its other types, digits will be lost > and > > the test will fail. An easy way to trigger an > error > > is to insert an extra TextConverter at index 2, > with { > > char.class, String.class } as its > destinationClasses. > > Again, it's very easy to solve the problem through > > configuration. The problem is that it's > repetitive > > and can be hard to detect because the odds will > often > > be against selecting the bad path--then one day it > > will arise unexpectedly. > > > > -Matt B > > > > --- Matt Sgarlata > > <Mat...@wh...> wrote: > > > > > Yikes, that doesn't sound good. I'm wondering > if it > > > would be possible to > > > fix this as an implementation concern rather > than > > > introducing a new > > > interface. Perhaps the ordering of the source > and > > > destination classes could > > > be used by the ChainedTransformer to give an > > > indication of preference for > > > the conversion path chosen. > > > > > > Can you give me a concrete example where data is > > > lost? I would be very > > > interested in setting up a test case that > > > demonstrates the problem and also > > > a solution for the problem. This is the type of > > > problem with Morph that I > > > have a lot of fun with ;) > > > > > > Matt S > > > > > > On Jan 3, 2008 5:27 PM, Matt Benson > > > <gud...@ya...> wrote: > > > > > > > In using ChainedTransformer I find I have to > jump > > > > through hoops at times to pick the proper > > > > transformation path, particularly with the > > > > TextConverter. If it happens to pick char, > > > Character, > > > > or null as a conversion step between e.g. a > > > "to-text" > > > > converter and a "from-text" converter, data is > > > lost. > > > > I am thinking of an interface like this: > > > > > > > > public interface ImpreciseConverter extends > > > Converter > > > > { > > > > boolean isImpreciseConversion(Class > > > > destinationClass, Class sourceClass); > > > > } > > > > > > > > The default implementation on BaseTransformer: > > > > > > > > public boolean isImpreciseConversion(Class > > > > destinationClass, Class sourceClass) { > > > > return destinationClass == null && > sourceClass > > > != > > > > null; > > > > } > > > > > > > > TextConverter would report that a conversion > from > > > a > > > > string to null or char is imprecise. > > > > ChainedTransformer could then be coded to > avoid > > > > imprecise conversions when possible. > > > > > > > > WDYT? > > > > > > > > -Matt B > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > ____________________________________________________________________________________ > > > > Never miss a thing. Make Yahoo your home > page. > > > > http://www.yahoo.com/r/hs > > > > > > > > > > > > > > ------------------------------------------------------------------------- > > > > This SF.net email is sponsored by: Microsoft > > > > Defy all challenges. Microsoft(R) Visual > Studio > > > 2005. > > > > > > > > > > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ > > > > > _______________________________________________ > > > > morph-developer mailing list > > > > mor...@li... > > > > > > > > > > https://lists.sourceforge.net/lists/listinfo/morph-developer > > > > > > > > > > > > > > > > -- > > > This message is intended only for the named > > > recipient. If you are not the > > > intended recipient, you are notified that > > > disclosing, copying, distributing, > > > or taking any action in reliance on the contents > of > > > this information is > > > strictly prohibited. > > > > > > > ------------------------------------------------------------------------- > > > This SF.net email is sponsored by: Microsoft > > > Defy all challenges. Microsoft(R) Visual Studio > > > 2005. > > > > > > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/> > > _______________________________________________ > > > morph-developer mailing list > > > mor...@li... > > > > > > https://lists.sourceforge.net/lists/listinfo/morph-developer > > > > > > > > > > > > > > ____________________________________________________________________________________ > > Looking for last minute shopping deals? > > Find them fast with Yahoo! Search. > > > http://tools.search.yahoo.com/newsearch/category.php?category=shopping > > > > > ------------------------------------------------------------------------- > > This SF.net email is sponsored by: Microsoft > > Defy all challenges. Microsoft(R) Visual Studio > 2005. > > > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ > > _______________________________________________ > > morph-developer mailing list > > mor...@li... > > > https://lists.sourceforge.net/lists/listinfo/morph-developer > > > > > > -- > This message is intended only for the named > recipient. If you are not the > intended recipient, you are notified that > disclosing, copying, distributing, > or taking any action in reliance on the contents of > this information is > strictly prohibited. > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Microsoft > Defy all challenges. Microsoft(R) Visual Studio > 2005. > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/> _______________________________________________ > morph-developer mailing list > mor...@li... > https://lists.sourceforge.net/lists/listinfo/morph-developer > ____________________________________________________________________________________ Be a better friend, newshound, and know-it-all with Yahoo! Mobile. Try it now. http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ |
From: Matt S. <mat...@sp...> - 2008-01-04 21:00:41
|
It sounds to me like I need to fix how the source and destination arrays are constructed so that order is preserved. I agree it is definitely not OK for this to require repetitive configuration to prevent difficult to detect errors. I will take a look first thing Monday. Matt On Jan 4, 2008 1:04 PM, Matt Benson <gud...@ya...> wrote: > Basically the order of destination classes in a given > converter in the chain already does influence the > conversion path chosen. However, many of the stock > transformers use sets to build the source and/or > destination class arrays, so the final order is > unpredictable. As for examples, anytime you convert a > string to a char/Character, you (unless the string is > exactly one character in length) lose information. > Anytime you convert an object to null, you lose all > information that was associated with that object. So > if you, as in ChainedTransformerTest, chain a > TextToNumberConverter, a DefaultToTextConverter, and > another TextToNumberConverter, and the > DefaultToTextConverter happens to return a char type > before one of its other types, digits will be lost and > the test will fail. An easy way to trigger an error > is to insert an extra TextConverter at index 2, with { > char.class, String.class } as its destinationClasses. > Again, it's very easy to solve the problem through > configuration. The problem is that it's repetitive > and can be hard to detect because the odds will often > be against selecting the bad path--then one day it > will arise unexpectedly. > > -Matt B > > --- Matt Sgarlata > <Mat...@wh...> wrote: > > > Yikes, that doesn't sound good. I'm wondering if it > > would be possible to > > fix this as an implementation concern rather than > > introducing a new > > interface. Perhaps the ordering of the source and > > destination classes could > > be used by the ChainedTransformer to give an > > indication of preference for > > the conversion path chosen. > > > > Can you give me a concrete example where data is > > lost? I would be very > > interested in setting up a test case that > > demonstrates the problem and also > > a solution for the problem. This is the type of > > problem with Morph that I > > have a lot of fun with ;) > > > > Matt S > > > > On Jan 3, 2008 5:27 PM, Matt Benson > > <gud...@ya...> wrote: > > > > > In using ChainedTransformer I find I have to jump > > > through hoops at times to pick the proper > > > transformation path, particularly with the > > > TextConverter. If it happens to pick char, > > Character, > > > or null as a conversion step between e.g. a > > "to-text" > > > converter and a "from-text" converter, data is > > lost. > > > I am thinking of an interface like this: > > > > > > public interface ImpreciseConverter extends > > Converter > > > { > > > boolean isImpreciseConversion(Class > > > destinationClass, Class sourceClass); > > > } > > > > > > The default implementation on BaseTransformer: > > > > > > public boolean isImpreciseConversion(Class > > > destinationClass, Class sourceClass) { > > > return destinationClass == null && sourceClass > > != > > > null; > > > } > > > > > > TextConverter would report that a conversion from > > a > > > string to null or char is imprecise. > > > ChainedTransformer could then be coded to avoid > > > imprecise conversions when possible. > > > > > > WDYT? > > > > > > -Matt B > > > > > > > > > > > > > > > > > > > > > > > > > ____________________________________________________________________________________ > > > Never miss a thing. Make Yahoo your home page. > > > http://www.yahoo.com/r/hs > > > > > > > > > ------------------------------------------------------------------------- > > > This SF.net email is sponsored by: Microsoft > > > Defy all challenges. Microsoft(R) Visual Studio > > 2005. > > > > > > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ > > > _______________________________________________ > > > morph-developer mailing list > > > mor...@li... > > > > > > https://lists.sourceforge.net/lists/listinfo/morph-developer > > > > > > > > > > > -- > > This message is intended only for the named > > recipient. If you are not the > > intended recipient, you are notified that > > disclosing, copying, distributing, > > or taking any action in reliance on the contents of > > this information is > > strictly prohibited. > > > > ------------------------------------------------------------------------- > > This SF.net email is sponsored by: Microsoft > > Defy all challenges. Microsoft(R) Visual Studio > > 2005. > > > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/> > _______________________________________________ > > morph-developer mailing list > > mor...@li... > > > https://lists.sourceforge.net/lists/listinfo/morph-developer > > > > > > > ____________________________________________________________________________________ > Looking for last minute shopping deals? > Find them fast with Yahoo! Search. > http://tools.search.yahoo.com/newsearch/category.php?category=shopping > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Microsoft > Defy all challenges. Microsoft(R) Visual Studio 2005. > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ > _______________________________________________ > morph-developer mailing list > mor...@li... > https://lists.sourceforge.net/lists/listinfo/morph-developer > -- This message is intended only for the named recipient. If you are not the intended recipient, you are notified that disclosing, copying, distributing, or taking any action in reliance on the contents of this information is strictly prohibited. |
From: Matt B. <gud...@ya...> - 2008-01-04 18:04:13
|
Basically the order of destination classes in a given converter in the chain already does influence the conversion path chosen. However, many of the stock transformers use sets to build the source and/or destination class arrays, so the final order is unpredictable. As for examples, anytime you convert a string to a char/Character, you (unless the string is exactly one character in length) lose information. Anytime you convert an object to null, you lose all information that was associated with that object. So if you, as in ChainedTransformerTest, chain a TextToNumberConverter, a DefaultToTextConverter, and another TextToNumberConverter, and the DefaultToTextConverter happens to return a char type before one of its other types, digits will be lost and the test will fail. An easy way to trigger an error is to insert an extra TextConverter at index 2, with { char.class, String.class } as its destinationClasses. Again, it's very easy to solve the problem through configuration. The problem is that it's repetitive and can be hard to detect because the odds will often be against selecting the bad path--then one day it will arise unexpectedly. -Matt B --- Matt Sgarlata <Mat...@wh...> wrote: > Yikes, that doesn't sound good. I'm wondering if it > would be possible to > fix this as an implementation concern rather than > introducing a new > interface. Perhaps the ordering of the source and > destination classes could > be used by the ChainedTransformer to give an > indication of preference for > the conversion path chosen. > > Can you give me a concrete example where data is > lost? I would be very > interested in setting up a test case that > demonstrates the problem and also > a solution for the problem. This is the type of > problem with Morph that I > have a lot of fun with ;) > > Matt S > > On Jan 3, 2008 5:27 PM, Matt Benson > <gud...@ya...> wrote: > > > In using ChainedTransformer I find I have to jump > > through hoops at times to pick the proper > > transformation path, particularly with the > > TextConverter. If it happens to pick char, > Character, > > or null as a conversion step between e.g. a > "to-text" > > converter and a "from-text" converter, data is > lost. > > I am thinking of an interface like this: > > > > public interface ImpreciseConverter extends > Converter > > { > > boolean isImpreciseConversion(Class > > destinationClass, Class sourceClass); > > } > > > > The default implementation on BaseTransformer: > > > > public boolean isImpreciseConversion(Class > > destinationClass, Class sourceClass) { > > return destinationClass == null && sourceClass > != > > null; > > } > > > > TextConverter would report that a conversion from > a > > string to null or char is imprecise. > > ChainedTransformer could then be coded to avoid > > imprecise conversions when possible. > > > > WDYT? > > > > -Matt B > > > > > > > > > > > > > > > ____________________________________________________________________________________ > > Never miss a thing. Make Yahoo your home page. > > http://www.yahoo.com/r/hs > > > > > ------------------------------------------------------------------------- > > This SF.net email is sponsored by: Microsoft > > Defy all challenges. Microsoft(R) Visual Studio > 2005. > > > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ > > _______________________________________________ > > morph-developer mailing list > > mor...@li... > > > https://lists.sourceforge.net/lists/listinfo/morph-developer > > > > > > -- > This message is intended only for the named > recipient. If you are not the > intended recipient, you are notified that > disclosing, copying, distributing, > or taking any action in reliance on the contents of > this information is > strictly prohibited. > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Microsoft > Defy all challenges. Microsoft(R) Visual Studio > 2005. > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/> _______________________________________________ > morph-developer mailing list > mor...@li... > https://lists.sourceforge.net/lists/listinfo/morph-developer > ____________________________________________________________________________________ Looking for last minute shopping deals? Find them fast with Yahoo! Search. http://tools.search.yahoo.com/newsearch/category.php?category=shopping |
From: Matt S. <Mat...@wh...> - 2008-01-04 13:16:33
|
Yikes, that doesn't sound good. I'm wondering if it would be possible to fix this as an implementation concern rather than introducing a new interface. Perhaps the ordering of the source and destination classes could be used by the ChainedTransformer to give an indication of preference for the conversion path chosen. Can you give me a concrete example where data is lost? I would be very interested in setting up a test case that demonstrates the problem and also a solution for the problem. This is the type of problem with Morph that I have a lot of fun with ;) Matt S On Jan 3, 2008 5:27 PM, Matt Benson <gud...@ya...> wrote: > In using ChainedTransformer I find I have to jump > through hoops at times to pick the proper > transformation path, particularly with the > TextConverter. If it happens to pick char, Character, > or null as a conversion step between e.g. a "to-text" > converter and a "from-text" converter, data is lost. > I am thinking of an interface like this: > > public interface ImpreciseConverter extends Converter > { > boolean isImpreciseConversion(Class > destinationClass, Class sourceClass); > } > > The default implementation on BaseTransformer: > > public boolean isImpreciseConversion(Class > destinationClass, Class sourceClass) { > return destinationClass == null && sourceClass != > null; > } > > TextConverter would report that a conversion from a > string to null or char is imprecise. > ChainedTransformer could then be coded to avoid > imprecise conversions when possible. > > WDYT? > > -Matt B > > > > > > > ____________________________________________________________________________________ > Never miss a thing. Make Yahoo your home page. > http://www.yahoo.com/r/hs > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Microsoft > Defy all challenges. Microsoft(R) Visual Studio 2005. > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ > _______________________________________________ > morph-developer mailing list > mor...@li... > https://lists.sourceforge.net/lists/listinfo/morph-developer > -- This message is intended only for the named recipient. If you are not the intended recipient, you are notified that disclosing, copying, distributing, or taking any action in reliance on the contents of this information is strictly prohibited. |
From: Matt B. <gud...@ya...> - 2008-01-03 22:28:02
|
In using ChainedTransformer I find I have to jump through hoops at times to pick the proper transformation path, particularly with the TextConverter. If it happens to pick char, Character, or null as a conversion step between e.g. a "to-text" converter and a "from-text" converter, data is lost. I am thinking of an interface like this: public interface ImpreciseConverter extends Converter { boolean isImpreciseConversion(Class destinationClass, Class sourceClass); } The default implementation on BaseTransformer: public boolean isImpreciseConversion(Class destinationClass, Class sourceClass) { return destinationClass == null && sourceClass != null; } TextConverter would report that a conversion from a string to null or char is imprecise. ChainedTransformer could then be coded to avoid imprecise conversions when possible. WDYT? -Matt B ____________________________________________________________________________________ Never miss a thing. Make Yahoo your home page. http://www.yahoo.com/r/hs |
From: Matt B. <gud...@ya...> - 2007-12-19 16:42:05
|
--- Matt Sgarlata <mat...@sp...> wrote: > I definitely think MultipleDestinationConverter > should be deprecated in > favor of DisassemblerCopier. > > I hope you are doing well. Happy holidays! I can't complain (much). :) Happy holidays to you too. -Matt B > > Matt S > > On 12/18/07, Matt Benson <gud...@ya...> > wrote: > > > > It's a little on the weird side, but it seems to > work > > okay. I've been planning it forever, but only > > recently needed it enough (I think) to break down > and > > do the work. Let me know what you think, e.g. > whether > > MultipleDestinationConverter can/should be > deprecated > > in favor of this class. > > > > -Matt (B) > > > > > > > > > ____________________________________________________________________________________ > > Never miss a thing. Make Yahoo your home page. > > http://www.yahoo.com/r/hs > > > > > ------------------------------------------------------------------------- > > SF.Net email is sponsored by: > > Check out the new SourceForge.net Marketplace. > > It's the best place to buy or sell services > > for just about anything Open Source. > > > > > http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace > > _______________________________________________ > > morph-developer mailing list > > mor...@li... > > > https://lists.sourceforge.net/lists/listinfo/morph-developer > > > > > > -- > This message is intended only for the named > recipient. If you are not the > intended recipient, you are notified that > disclosing, copying, distributing, > or taking any action in reliance on the contents of > this information is > strictly prohibited. > > ------------------------------------------------------------------------- > SF.Net email is sponsored by: > Check out the new SourceForge.net Marketplace. > It's the best place to buy or sell services > for just about anything Open Source. > http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace> _______________________________________________ > morph-developer mailing list > mor...@li... > https://lists.sourceforge.net/lists/listinfo/morph-developer > ____________________________________________________________________________________ Never miss a thing. Make Yahoo your home page. http://www.yahoo.com/r/hs |
From: Matt S. <mat...@sp...> - 2007-12-19 00:06:17
|
I definitely think MultipleDestinationConverter should be deprecated in favor of DisassemblerCopier. I hope you are doing well. Happy holidays! Matt S On 12/18/07, Matt Benson <gud...@ya...> wrote: > > It's a little on the weird side, but it seems to work > okay. I've been planning it forever, but only > recently needed it enough (I think) to break down and > do the work. Let me know what you think, e.g. whether > MultipleDestinationConverter can/should be deprecated > in favor of this class. > > -Matt (B) > > > > ____________________________________________________________________________________ > Never miss a thing. Make Yahoo your home page. > http://www.yahoo.com/r/hs > > ------------------------------------------------------------------------- > SF.Net email is sponsored by: > Check out the new SourceForge.net Marketplace. > It's the best place to buy or sell services > for just about anything Open Source. > > http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace > _______________________________________________ > morph-developer mailing list > mor...@li... > https://lists.sourceforge.net/lists/listinfo/morph-developer > -- This message is intended only for the named recipient. If you are not the intended recipient, you are notified that disclosing, copying, distributing, or taking any action in reliance on the contents of this information is strictly prohibited. |
From: Matt B. <gud...@ya...> - 2007-12-18 21:47:44
|
It's a little on the weird side, but it seems to work okay. I've been planning it forever, but only recently needed it enough (I think) to break down and do the work. Let me know what you think, e.g. whether MultipleDestinationConverter can/should be deprecated in favor of this class. -Matt (B) ____________________________________________________________________________________ Never miss a thing. Make Yahoo your home page. http://www.yahoo.com/r/hs |
From: Matt S. <Mat...@wh...> - 2007-11-16 16:53:12
|
Sorry for not getting back to you sooner; work has been very busy the past couple weeks! My idea for Morph from the beginning has been that it should offer a rich set of default reflectors and transformers and then make it easy for you to make a few tweaks to suit your particular use case (the 80/20 rule). If all the defaults work well for you, then the Morph abstract class works great. If the defaults aren't quite right, it's kind of a PITA to work with the SimpleDelegatingTransformer, SDR, etc. Basically I think Morph addresses the 80% well but falls short the other 20% of the time. To address the other 20%, I have been thinking about introducing a non-static version of the Morph class that is customizable. This is kind of like the difference between BeanUtils and BeanUtilsBean in Commons-BeanUtils. Instead of calling the class MorphBean I opted for the name MorphSystem, but I am open for other suggested names. Morph2 delegates to a particular, unchangeable MorphSystem and will perhaps someday Morph2 will replace the old Morph class. Here is an example of what I am talking about ContainerToPrettyTextConverter containerConverter = new ContainerToPrettyTextConverter(); containerConverter.setPrefix(null); containerConverter.setSuffix(null); DefaultToTextConverter toTextConverter = new DefaultToTextConverter(new Transformer[] { containerConverter }, true); BeanToPrettyTextConverter converter = new BeanToPrettyTextConverter(); converter.setToTextConverter(toTextConverter); converter.setSeparator("&"); converter.setPrefix(null); converter.setSuffix(null); This part of the syntax I am OK with: ContainerToPrettyTextConverter containerConverter = new ContainerToPrettyTextConverter(); containerConverter.setPrefix(null); containerConverter.setSuffix(null); BeanToPrettyTextConverter converter = new BeanToPrettyTextConverter(); converter.setSeparator("&"); converter.setPrefix(null); converter.setSuffix(null); This part I am not OK with: DefaultToTextConverter toTextConverter = new DefaultToTextConverter(new Transformer[] { containerConverter }, true); converter.setToTextConverter(toTextConverter); For the part I am not OK with, instead I would like to see: MorphSystem m = new MorphSystem(); m.setComponent("containerConverter", containerConverter); m.setComponent("toTextConverter", toTextConverter); The idea here is that the MorphSystem looks for all the containerConverter references in all the converters that are part of it and appropriately wires them up to point to the custom containerConverter the user specifies. I actually started on a class called MorphSystem years ago and then shelved it because I thought that I was basically duplicating the work you see in a dependency injection framework. So, instead of going this route I figured it should be possible to use Spring or some other DI framework for the same effect. Experience has shown me that for this use DI is cumbersome at best and painfully counterintuitive at worst. So, what do you think about all this? Matt S Matt Benson wrote: > So, tell me about this... :) > > -Matt B > > > ____________________________________________________________________________________ > Be a better sports nut! Let your teams follow you > with Yahoo Mobile. Try it now. http://mobile.yahoo.com/sports;_ylt=At9_qDKvtAbMuh1G1SQtBI7ntAcJ > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Splunk Inc. > Still grepping through log files to find problems? Stop. > Now Search log events and configuration files using AJAX and a browser. > Download your FREE copy of Splunk now >> http://get.splunk.com/ > _______________________________________________ > morph-developer mailing list > mor...@li... > https://lists.sourceforge.net/lists/listinfo/morph-developer > > |
From: Matt B. <gud...@ya...> - 2007-11-14 17:59:28
|
So, tell me about this... :) -Matt B ____________________________________________________________________________________ Be a better sports nut! Let your teams follow you with Yahoo Mobile. Try it now. http://mobile.yahoo.com/sports;_ylt=At9_qDKvtAbMuh1G1SQtBI7ntAcJ |
From: Matt B. <gud...@ya...> - 2007-11-02 18:57:45
|
--- Matt Sgarlata <Mat...@wh...> wrote: > Good news! Spider Strategies started an R&D day for > developers to spend > on their own projects, so now I have 8 hours a week > that I can > potentially devote to Morph. I have everything to > the point where I > would like to get a new Morph release out the door. Very cool! Sorry I haven't had the time to devote to this. :( > Matt B, do you have > the code where you want it to be for this? If you > give me the green > light, I will probably try to get a release out the > door next Friday > (our normal R&D day is Thursday but I will have to > do Friday because I > will be out of the office Thursday). I think I am cool. I have added a lot of stuff over time, but currently my workspace is clean. Eventually I/we need to give more thought to how to make the DSLDefinedTransformer more useful/configurable--we're using it in production now so it seems to work. :) I think we've made a lot of progress this past year, definitely time for a release. There are a lot of new classes, etc., too, so maybe it would be appropriate to call the release 1.1 . OTOH, I can't think of anything terribly backward incompatible with the exception of the occasional thing that was incomplete before. Your call. I assume you'll also release Composite 1.0.1 (IIRC)? > > FYI, this week and last I worked on finishing out > the new > ServletRequestReflector that is capable of > reflecting both servlet > request parameters and attributes. This was the > topic of the email back > in May about 'Reflector Delegation Strategy'. The > SRR delegates to a > StubbornDelegatingReflector that visits all the > reflectors to get the > full story of what can be done to a target object. > I'm definitely open > to renaming this class if anyone can think of a > better name. I have a vague recollection of that. Sounds similar to the CumulativeCopier I introduced that runs a source and dest object through a number of delegate Copiers. :) Woohoo! -Matt B > > Matt S > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Splunk Inc. > Still grepping through log files to find problems? > Stop. > Now Search log events and configuration files using > AJAX and a browser. > Download your FREE copy of Splunk now >> > http://get.splunk.com/ > _______________________________________________ > morph-developer mailing list > mor...@li... > https://lists.sourceforge.net/lists/listinfo/morph-developer > __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com |
From: Matt S. <Mat...@wh...> - 2007-11-02 18:23:08
|
Good news! Spider Strategies started an R&D day for developers to spend on their own projects, so now I have 8 hours a week that I can potentially devote to Morph. I have everything to the point where I would like to get a new Morph release out the door. Matt B, do you have the code where you want it to be for this? If you give me the green light, I will probably try to get a release out the door next Friday (our normal R&D day is Thursday but I will have to do Friday because I will be out of the office Thursday). FYI, this week and last I worked on finishing out the new ServletRequestReflector that is capable of reflecting both servlet request parameters and attributes. This was the topic of the email back in May about 'Reflector Delegation Strategy'. The SRR delegates to a StubbornDelegatingReflector that visits all the reflectors to get the full story of what can be done to a target object. I'm definitely open to renaming this class if anyone can think of a better name. Matt S |
From: Matt B. <gud...@ya...> - 2007-10-19 21:00:20
|
Cool! I wonder what accounts for it... now we've just got to get 1.0.2 out the door... :) -Matt B --- Matt Sgarlata <mat...@sp...> wrote: > The last time I checked the statistics for Morph on > SourceForge, there > were less than 100 downloads of Morph 1.0.1. Now > there 756! There have > been as many as a dozen downloads on a single day. > Here is a link so > you can check out the current statistics: > > http://sourceforge.net/project/stats/?group_id=124910&ugn=morph > > Matt > > -- > This message is intended only for the named > recipient. If you are not the intended recipient, > you are notified that disclosing, copying, > distributing, or taking any action in reliance on > the contents of this information is strictly > prohibited. > > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Splunk Inc. > Still grepping through log files to find problems? > Stop. > Now Search log events and configuration files using > AJAX and a browser. > Download your FREE copy of Splunk now >> > http://get.splunk.com/ > _______________________________________________ > morph-developer mailing list > mor...@li... > https://lists.sourceforge.net/lists/listinfo/morph-developer > __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com |
From: Matt S. <mat...@sp...> - 2007-10-19 16:47:50
|
The last time I checked the statistics for Morph on SourceForge, there were less than 100 downloads of Morph 1.0.1. Now there 756! There have been as many as a dozen downloads on a single day. Here is a link so you can check out the current statistics: http://sourceforge.net/project/stats/?group_id=124910&ugn=morph Matt -- This message is intended only for the named recipient. If you are not the intended recipient, you are notified that disclosing, copying, distributing, or taking any action in reliance on the contents of this information is strictly prohibited. |
From: Matt B. <gud...@ya...> - 2007-09-06 14:28:56
|
Yes, my interest level is still there, though I do have a lot going on. I like to think that the reason the commit activity has gone significantly down is that Morph is really getting into pretty good shape. I'd certainly like to continue exploring ways to make its configuration idiot-easy, or at least approach that, but from a functional perspective it's pretty damned impressive IMO. :) -Matt (B) --- Matt Sgarlata <Mat...@wh...> wrote: > Hi Matt - no problem. I accidentally introduce > non-1.4 compatible calls > from time to time myself. It seems it isn't > sufficient to specify 1.3 > or 1.4 compatibility with ant. You actually have to > compile with JDK > 1.4 if you want to catch all possible problems. At > work we have our > test environment setup to run JDK 1.4 so if Morph > calls anything that's > not 1.4 compatible I find it fairly quickly ;) > > I'm glad to hear you're still planning on doing a > release :) I did > notice you are still doing commits from time to > time. > > Matt S > > Matt Benson wrote: > > Hi Matt, > > We've both been pretty quiet lately on this list, > but > > obviously still both using and tweaking Morph. I > > haven't forgotten my goal of doing a release > either, > > just got a lot on my plate ATM. Wanted to > apologize > > for somehow having gotten a bunch of 1.5-specific > > calls into Morph. I have Eclipse set for 1.3 > > compilation on Morph, so I'm not sure how or why > e.g. > > Integer.valueOf(int) was even working... anyway, > sorry > > about that. :) > > > > br, > > Matt > > > > > > > > > ____________________________________________________________________________________ > > Be a better Globetrotter. Get better travel > answers from someone who knows. Yahoo! Answers - > Check it out. > > > http://answers.yahoo.com/dir/?link=list&sid=396545469 > > > > > ------------------------------------------------------------------------- > > This SF.net email is sponsored by: Splunk Inc. > > Still grepping through log files to find problems? > Stop. > > Now Search log events and configuration files > using AJAX and a browser. > > Download your FREE copy of Splunk now >> > http://get.splunk.com/ > > _______________________________________________ > > morph-developer mailing list > > mor...@li... > > > https://lists.sourceforge.net/lists/listinfo/morph-developer > > > > > > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Splunk Inc. > Still grepping through log files to find problems? > Stop. > Now Search log events and configuration files using > AJAX and a browser. > Download your FREE copy of Splunk now >> > http://get.splunk.com/ > _______________________________________________ > morph-developer mailing list > mor...@li... > https://lists.sourceforge.net/lists/listinfo/morph-developer > ____________________________________________________________________________________ Shape Yahoo! in your own image. Join our Network Research Panel today! http://surveylink.yahoo.com/gmrs/yahoo_panel_invite.asp?a=7 |
From: Matt S. <Mat...@wh...> - 2007-09-05 14:33:07
|
Hi Matt - no problem. I accidentally introduce non-1.4 compatible calls from time to time myself. It seems it isn't sufficient to specify 1.3 or 1.4 compatibility with ant. You actually have to compile with JDK 1.4 if you want to catch all possible problems. At work we have our test environment setup to run JDK 1.4 so if Morph calls anything that's not 1.4 compatible I find it fairly quickly ;) I'm glad to hear you're still planning on doing a release :) I did notice you are still doing commits from time to time. Matt S Matt Benson wrote: > Hi Matt, > We've both been pretty quiet lately on this list, but > obviously still both using and tweaking Morph. I > haven't forgotten my goal of doing a release either, > just got a lot on my plate ATM. Wanted to apologize > for somehow having gotten a bunch of 1.5-specific > calls into Morph. I have Eclipse set for 1.3 > compilation on Morph, so I'm not sure how or why e.g. > Integer.valueOf(int) was even working... anyway, sorry > about that. :) > > br, > Matt > > > > ____________________________________________________________________________________ > Be a better Globetrotter. Get better travel answers from someone who knows. Yahoo! Answers - Check it out. > http://answers.yahoo.com/dir/?link=list&sid=396545469 > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Splunk Inc. > Still grepping through log files to find problems? Stop. > Now Search log events and configuration files using AJAX and a browser. > Download your FREE copy of Splunk now >> http://get.splunk.com/ > _______________________________________________ > morph-developer mailing list > mor...@li... > https://lists.sourceforge.net/lists/listinfo/morph-developer > > |
From: Matt B. <gud...@ya...> - 2007-09-04 21:13:19
|
Hi Matt, We've both been pretty quiet lately on this list, but obviously still both using and tweaking Morph. I haven't forgotten my goal of doing a release either, just got a lot on my plate ATM. Wanted to apologize for somehow having gotten a bunch of 1.5-specific calls into Morph. I have Eclipse set for 1.3 compilation on Morph, so I'm not sure how or why e.g. Integer.valueOf(int) was even working... anyway, sorry about that. :) br, Matt ____________________________________________________________________________________ Be a better Globetrotter. Get better travel answers from someone who knows. Yahoo! Answers - Check it out. http://answers.yahoo.com/dir/?link=list&sid=396545469 |
From: Matt B. <gud...@ya...> - 2007-05-24 19:36:09
|
Sorry it took me so long to respond. Been pretty busy here lately. Anyway, I guess I feel like option #1 is most compatible with Morph's existing architecture. But I would definitely implement this generically as some kind of CompositeReflector that queries each of its components in turn for handling of a given property. e.g. one child might know how to read property foo, while the other might know how to write it. Who knows? The available properties would be the union of all properties reported by all components. WDYT? -Matt B --- Matt Sgarlata <mat...@sp...> wrote: > There is a use case that Morph does not cover that > has been an "itch" of > mine since pretty much the beginning. > Morph.get(request, "something") > will only return request attributes, never request > parameters. There > are a lot of ways this could be worked around, but > there are a couple > reasons that conspired to cause this. > > One reason the code works the way it does now is > because of how I wrote > reflectors. My intent for reflectors was that they > would be very > low-level objects with relatively simple behavior. > So, I have a > separate ServletRequestAttributeReflector and > ServletRequestParameterReflector, just like I have > separate > CollectionReflector and IteratorReflectors (rather > than trying to > squeeze them into a single ContainerReflector). > This keeps their > implementation very clean and makes them easily > testable. > > The other reason for this behavior is the > SimpleDelegatingReflector's > strategy for choosing a reflector for an object. > Currently, the first > reflector that can reflect an object is chosen and > that's it, which > makes the implementation of most Reflector methods > trivial, for example, > > protected Object getImpl(Object bean, String > propertyName) throws > Exception { > return getBeanReflector(bean).get(bean, > propertyName); > } > > So there are a number of ways to work around this > and I could never > decide the best one: > 1) Write a ServletRequestReflector that delegates to > the > ServletRequestParameterReflector and > ServletRequestAttributeReflector. > An upside is this approach is fairly simple to > understand conceptually. > A downside of this approach is the delegation code > here could become a > bit repetitive if this situation is encountered > multiple times. One > need not look far to find another example where this > would have to be > implemented again or called again (if some sort of > delegate or > superclass was written): again for the Servlet API > we have separate a > ServletContextInitParameterReflector and > ServletContextAttributeReflector. > 2) Change the default implementation of > SimpleDelegatingReflector so > that it tries multiple reflectors if the first one > fails. The big > downside here is this could be fairly confusing > since all objects are > reflectable by the ObjectReflector which could be > unexpected and/or > confusing. For example, this would cause all > objects to automatically > receive a "class" property. In addition to being > confusing, this could > cause problems when using objects over which the > user has little or no > control, such a ServletRequest objects. If the > implementation class for > the request object has public mutators, those would > be exposed which > could be a particular annoyance for adherents to > interface-based design > that just declare lots of stuff public to make > utilizing dependency > injections frameworks (like me). > 3) Introduce a configuration parameter or some type > of Strategy delegate > object that decides how a delegate is chosen in the > SimpleDelegatingReflector. > 4) Introduce a new type of DelegatingReflector (the > current delegate > implementation is called 'simple' after all!) > > I don't think #3 or #4 is really workable, because > the behavior I'm > really trying to affect here is for the Morph static > method, so option 3 > and 4 are really just dodging the original issues > presented by option > 2. I suppose options 3 and 4 would really be the > implementation > approach for option #1. I guess after writing this > massive amount of > text I'm leaning towards option #1, but I would love > to hear some more > ideas. > > Thanks, > > Matt S > > -- > This message is intended only for the named > recipient. If you are not the intended recipient, > you are notified that disclosing, copying, > distributing, or taking any action in reliance on > the contents of this information is strictly > prohibited. > > > ------------------------------------------------------------------------- > This SF.net email is sponsored by DB2 Express > Download DB2 Express C - the FREE version of DB2 > express and take > control of your XML. No limits. Just data. Click to > get it now. > http://sourceforge.net/powerbar/db2/ > _______________________________________________ > morph-developer mailing list > mor...@li... > https://lists.sourceforge.net/lists/listinfo/morph-developer > ____________________________________________________________________________________Take the Internet to Go: Yahoo!Go puts the Internet in your pocket: mail, news, photos & more. http://mobile.yahoo.com/go?refer=1GNXIC |
From: Matt S. <mat...@sp...> - 2007-05-21 23:17:04
|
There is a use case that Morph does not cover that has been an "itch" of mine since pretty much the beginning. Morph.get(request, "something") will only return request attributes, never request parameters. There are a lot of ways this could be worked around, but there are a couple reasons that conspired to cause this. One reason the code works the way it does now is because of how I wrote reflectors. My intent for reflectors was that they would be very low-level objects with relatively simple behavior. So, I have a separate ServletRequestAttributeReflector and ServletRequestParameterReflector, just like I have separate CollectionReflector and IteratorReflectors (rather than trying to squeeze them into a single ContainerReflector). This keeps their implementation very clean and makes them easily testable. The other reason for this behavior is the SimpleDelegatingReflector's strategy for choosing a reflector for an object. Currently, the first reflector that can reflect an object is chosen and that's it, which makes the implementation of most Reflector methods trivial, for example, protected Object getImpl(Object bean, String propertyName) throws Exception { return getBeanReflector(bean).get(bean, propertyName); } So there are a number of ways to work around this and I could never decide the best one: 1) Write a ServletRequestReflector that delegates to the ServletRequestParameterReflector and ServletRequestAttributeReflector. An upside is this approach is fairly simple to understand conceptually. A downside of this approach is the delegation code here could become a bit repetitive if this situation is encountered multiple times. One need not look far to find another example where this would have to be implemented again or called again (if some sort of delegate or superclass was written): again for the Servlet API we have separate a ServletContextInitParameterReflector and ServletContextAttributeReflector. 2) Change the default implementation of SimpleDelegatingReflector so that it tries multiple reflectors if the first one fails. The big downside here is this could be fairly confusing since all objects are reflectable by the ObjectReflector which could be unexpected and/or confusing. For example, this would cause all objects to automatically receive a "class" property. In addition to being confusing, this could cause problems when using objects over which the user has little or no control, such a ServletRequest objects. If the implementation class for the request object has public mutators, those would be exposed which could be a particular annoyance for adherents to interface-based design that just declare lots of stuff public to make utilizing dependency injections frameworks (like me). 3) Introduce a configuration parameter or some type of Strategy delegate object that decides how a delegate is chosen in the SimpleDelegatingReflector. 4) Introduce a new type of DelegatingReflector (the current delegate implementation is called 'simple' after all!) I don't think #3 or #4 is really workable, because the behavior I'm really trying to affect here is for the Morph static method, so option 3 and 4 are really just dodging the original issues presented by option 2. I suppose options 3 and 4 would really be the implementation approach for option #1. I guess after writing this massive amount of text I'm leaning towards option #1, but I would love to hear some more ideas. Thanks, Matt S -- This message is intended only for the named recipient. If you are not the intended recipient, you are notified that disclosing, copying, distributing, or taking any action in reliance on the contents of this information is strictly prohibited. |
From: Matt S. <Mat...@wh...> - 2007-05-21 22:45:29
|
FYI, I wrote a post today about Morph in the Spider Strategies blog, http://www.spiderstrategies.com/blog. I plan to write another post or two to provide a bit of advertising for Morph. I also copied the technical part of the post into the user manual, so this will be a nice way for me to add to the user manual as well :) Matt |