morph-developer Mailing List for Morph (Page 3)
Brought to you by:
orangeherbert,
sgarlatm
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 |