RFC: Serious issue with Converters.java, Sun JDK compiler and Eclipse compiler

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

RFC: Serious issue with Converters.java, Sun JDK compiler and Eclipse compiler

Francis ANDRE
Hi

I found a serious issue related to the order in which the method Class<?>.getClasses() returns the Class<?>[].

Let me explain the story.

First, I was running OfBiz in debug mode under Eclipse and testing the demo application, this exception raised:

2012-06-13 10:09:07,015 (http-bio-0.0.0.0-8443-exec-9) [      GenericEntity.java:426:WARN ]
---- exception report ----------------------------------------------------------
=-=-=-=-=-=-=-=-= Database type warning GenericEntity.set =-=-=-=-=-=-=-=-= In entity field [PartyContactMech.thruDate] set the value passed in [java.util.Date] is not compatible with the Java type of the field [java.sql.Timestamp]
Exception: java.lang.Exception
Message: Location of database type warning
---- stack trace ---------------------------------------------------------------
java.lang.Exception: Location of database type warning
org.ofbiz.entity.GenericEntity.set(GenericEntity.java:426)
org.ofbiz.entity.GenericEntity.put(GenericEntity.java:1418)
org.ofbiz.entity.GenericEntity.put(GenericEntity.java:1)
javax.el.MapELResolver.setValue(MapELResolver.java:286)
javax.el.CompositeELResolver.setValue(CompositeELResolver.java:329)
org.ofbiz.base.util.string.UelUtil$ExtendedCompositeResolver.setValue(UelUtil.java:337)
org.ofbiz.base.util.string.JuelConnector$ExtendedAstDot.setValue(JuelConnector.java:127)
de.odysseus.el.tree.impl.ast.AstEval.setValue(AstEval.java:87)
de.odysseus.el.TreeValueExpression.setValue(TreeValueExpression.java:146)
org.ofbiz.base.util.string.UelUtil.setValue(UelUtil.java:104)
org.ofbiz.base.util.collections.FlexibleMapAccessor.put(FlexibleMapAccessor.java:170)
org.ofbiz.minilang.method.envops.Now.exec(Now.java:100)
org.ofbiz.minilang.SimpleMethod.runSubOps(SimpleMethod.java:308)
org.ofbiz.minilang.method.conditional.CompareFieldCondition.exec(CompareFieldCondition.java:135)
org.ofbiz.minilang.SimpleMethod.runSubOps(SimpleMethod.java:308)

The point is that the entity field PartyContactMech.thruDate is expecting a java.sql.Timestamp while it received a java.util.Date. fine. Here the analysis of the problem

1/ At one point in time, the Now static contructor executes the code displayed below: this.converter = Converters.getConverter(Long.class, targetClass); whith targetClass set to java.sql.Timestamp

        Class<?> targetClass = null;
        try {
            if (!this.type.isEmpty()) {
                targetClass = ObjectType.loadClass(this.type);
            }
            if (targetClass == null) {
                targetClass = java.sql.Timestamp.class;
            }
            this.converter = Converters.getConverter(Long.class, targetClass);
        } catch (ClassNotFoundException e) {
            throw new ValidationException(e.getMessage(), simpleMethod, element);
        }

2/ Converters.getConverter(Long.class, java.sql.Timestamp.class); is looking at line 82 as show below in the static field convertedMap a potential converter with the following key: "java.lang.Long->java.sql.Timestamp"
OUTER:
        do {
            Converter<?, ?> result = converterMap.get(key);    // line 82
            if (result != null) {
                return UtilGenerics.cast(result);
            }
            if (noConversions.contains(key)) {
                throw new ClassNotFoundException("No converter found for " + key);
            }
            for (Converter<?, ?> value : converterMap.values()) {   // line 89
                if (value.canConvert(sourceClass, targetClass)) {    //line 90
                    converterMap.putIfAbsent(key, value);                    // line 91
                    continue OUTER;
                }
            }

3/ Under Eclipse, the converterMap.get(key) initialy does not find any key. Thus the loop line 89 starts to execute. At line 90, the value DateTimeConverter.NumberToDate.canConvert(Long.class, Timestamp .class) returns true which makes the line 91 inserting the value DateTimeConverter.NumberToDate for the key "java.lang.Long->java.sql.Timestamp"

4/ Upon restarting at the OTUER label, the statement result = compertedMap.get("java.lang.Long->java.sql.Timestamp") return DateTimeConverter.NumberToDate as result.

5/ Later on when the statement this.fieldFma.put(methodContext.getEnvMap(), this.converter.convert(System.currentTimeMillis())); from the method below executes, one gets the exception above "In entity field [PartyContactMech.thruDate] set the value passed in [java.util.Date] is not compatible w
ith the Java type of the field [java.sql.Timestamp]" because the type of the converted value is a java.util.Date and not java.sql.Timestamp.


At that point, what's make me mad is that this same code is running well when ofbiz is started with the ant start command. Thus I looked further in the analysis and the problem is coming from this fact:

The Eclipse compiler produces a DateTimeConverters.class from which the method DateTimeConverters.getClasses() returns the inner classes sorted by lexical order of their name
The Sun SDK 1.6.0_30 javac produces a DateTimeConverters.class from which the method DateTimeConverters.getClasses() returns the inner classes  sorted by the reverse lexical order of their name


Let me explain this point.

I tested with this simple program both compiler's generated classe for DateTimeConverter
public class Main {
    public static void main(String[] args) {
        DateTimeConverters dateTimeConverters;
        Class<?>[] classes = DateTimeConverters.class.getClasses();
        for (Class<?> cls : classes) {
            System.out.println(cls);
        }
    }
 Compiling the DateTimeConverter with the Eclipse compiler, the above program produces

class org.ofbiz.base.conversion.DateTimeConverters$CalendarToDate
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToLong
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToString
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$DateToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$DateToLong
class org.ofbiz.base.conversion.DateTimeConverters$DateToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$DateToString
class org.ofbiz.base.conversion.DateTimeConverters$DateToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$DurationToBigDecimal
class org.ofbiz.base.conversion.DateTimeConverters$DurationToDouble
class org.ofbiz.base.conversion.DateTimeConverters$DurationToFloat
class org.ofbiz.base.conversion.DateTimeConverters$DurationToList
class org.ofbiz.base.conversion.DateTimeConverters$DurationToLong
class org.ofbiz.base.conversion.DateTimeConverters$DurationToSet
class org.ofbiz.base.conversion.DateTimeConverters$DurationToString
class org.ofbiz.base.conversion.DateTimeConverters$GenericLocalizedConverter
class org.ofbiz.base.conversion.DateTimeConverters$LongToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$NumberToDate
class org.ofbiz.base.conversion.DateTimeConverters$NumberToDuration
class org.ofbiz.base.conversion.DateTimeConverters$NumberToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$NumberToSqlTime
class org.ofbiz.base.conversion.DateTimeConverters$NumberToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToDate
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToList
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToSet
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToString
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToTime
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToList
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToSet
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToString
class org.ofbiz.base.conversion.DateTimeConverters$StringToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$StringToDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToDuration
class org.ofbiz.base.conversion.DateTimeConverters$StringToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToSqlTime
class org.ofbiz.base.conversion.DateTimeConverters$StringToTimeZone
class org.ofbiz.base.conversion.DateTimeConverters$StringToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$TimeZoneToString
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToDate
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToList
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToSet
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToSqlDate


while compiling DateTimeConverters with the Sun SDK, the above program produces

class org.ofbiz.base.conversion.DateTimeConverters$TimeZoneToString
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToSet
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToList
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToTimeZone
class org.ofbiz.base.conversion.DateTimeConverters$StringToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$StringToSqlTime
class org.ofbiz.base.conversion.DateTimeConverters$StringToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToDuration
class org.ofbiz.base.conversion.DateTimeConverters$StringToDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToString
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToSet
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToList
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToTime
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToString
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToSet
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToList
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToDate
class org.ofbiz.base.conversion.DateTimeConverters$NumberToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$NumberToSqlTime
class org.ofbiz.base.conversion.DateTimeConverters$NumberToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$NumberToDuration
class org.ofbiz.base.conversion.DateTimeConverters$NumberToDate
class org.ofbiz.base.conversion.DateTimeConverters$LongToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$GenericLocalizedConverter
class org.ofbiz.base.conversion.DateTimeConverters$DurationToString
class org.ofbiz.base.conversion.DateTimeConverters$DurationToSet
class org.ofbiz.base.conversion.DateTimeConverters$DurationToLong
class org.ofbiz.base.conversion.DateTimeConverters$DurationToList
class org.ofbiz.base.conversion.DateTimeConverters$DurationToFloat
class org.ofbiz.base.conversion.DateTimeConverters$DurationToDouble
class org.ofbiz.base.conversion.DateTimeConverters$DurationToBigDecimal
class org.ofbiz.base.conversion.DateTimeConverters$DateToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$DateToString
class org.ofbiz.base.conversion.DateTimeConverters$DateToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$DateToLong
class org.ofbiz.base.conversion.DateTimeConverters$DateToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToString
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToLong
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToDate

Hu... How could it be that such lexical order or reverse order makes OfBiz fails or not???

Here the explanation

The Converters class initialy loads the convertedMap with this method

    public static void loadContainedConverters(Class<?> containerClass) {
        // This only returns -public- classes and interfaces
        for (Class<?> clz: containerClass.getClasses()) {
            try {
                // non-abstract, which means no interfaces or abstract classes
                if ((clz.getModifiers() & Modifier.ABSTRACT) == 0) {
                    Object value;
                    try {
                        value = clz.getConstructor().newInstance();
                    } catch (NoSuchMethodException e) {
                        // ignore this, as this class might be some other helper class,
                        // with a non-pubilc constructor
                        continue;
                    }
                    if (value instanceof ConverterLoader) {
                        ConverterLoader loader = (ConverterLoader) value;
                        loader.loadConverters();
                    }
                }
            } catch (Exception e) {
                Debug.logError(e, module);
            }
        }
    }

you can note that the main loop is driven by the statement: for (Class<?> clz: containerClass.getClasses()) which returns either the lexically ordered inner classes with Eclipse compiler or the reversed lexically ordered inner classes with the Sun SDK. This means that the convertedMap will be initialized with the same order (direct or reversed)

 Thus returning back to the Now static contructor statement which calls Converters.getConverter(Long.class, Timestamp.class), the statement convertedMap.values() will return

1/ In case of the Sun SDk, the converter DateTimeConverters$NumberToTimestamp which leads to the correct expected java type java.sql.Timestamp
2/ In case of the Eclipse compiler, the converter DateTimeConverters$NumberToDate which leads to the incorrect unexpected  java type java.util.Date.


Conclusion:
The behavior of Converters.getConverter(souceClass, targetClass) is depending of the order in which the compiler is generating the DateTimeConverters inner classes to be returned by the getClasses() method.


Proposal for solving this issue
Each time the method Class<?>.getClasses() is called, add a additional step before to sort the resulting array of inner classes in the lexically reversed order as done by the Sun SDK.


Rgds

Francis ANDRE


Reply | Threaded
Open this post in threaded view
|

Re: RFC: Serious issue with Converters.java, Sun JDK compiler and Eclipse compiler

Adrian Crum-3
Thank you for the detailed report. I will look into it.

-Adrian

On 6/13/2012 4:27 PM, Francis ANDRE wrote:
Hi

I found a serious issue related to the order in which the method Class<?>.getClasses() returns the Class<?>[].

Let me explain the story.

First, I was running OfBiz in debug mode under Eclipse and testing the demo application, this exception raised:

2012-06-13 10:09:07,015 (http-bio-0.0.0.0-8443-exec-9) [      GenericEntity.java:426:WARN ]
---- exception report ----------------------------------------------------------
=-=-=-=-=-=-=-=-= Database type warning GenericEntity.set =-=-=-=-=-=-=-=-= In entity field [PartyContactMech.thruDate] set the value passed in [java.util.Date] is not compatible with the Java type of the field [java.sql.Timestamp]
Exception: java.lang.Exception
Message: Location of database type warning
---- stack trace ---------------------------------------------------------------
java.lang.Exception: Location of database type warning
org.ofbiz.entity.GenericEntity.set(GenericEntity.java:426)
org.ofbiz.entity.GenericEntity.put(GenericEntity.java:1418)
org.ofbiz.entity.GenericEntity.put(GenericEntity.java:1)
javax.el.MapELResolver.setValue(MapELResolver.java:286)
javax.el.CompositeELResolver.setValue(CompositeELResolver.java:329)
org.ofbiz.base.util.string.UelUtil$ExtendedCompositeResolver.setValue(UelUtil.java:337)
org.ofbiz.base.util.string.JuelConnector$ExtendedAstDot.setValue(JuelConnector.java:127)
de.odysseus.el.tree.impl.ast.AstEval.setValue(AstEval.java:87)
de.odysseus.el.TreeValueExpression.setValue(TreeValueExpression.java:146)
org.ofbiz.base.util.string.UelUtil.setValue(UelUtil.java:104)
org.ofbiz.base.util.collections.FlexibleMapAccessor.put(FlexibleMapAccessor.java:170)
org.ofbiz.minilang.method.envops.Now.exec(Now.java:100)
org.ofbiz.minilang.SimpleMethod.runSubOps(SimpleMethod.java:308)
org.ofbiz.minilang.method.conditional.CompareFieldCondition.exec(CompareFieldCondition.java:135)
org.ofbiz.minilang.SimpleMethod.runSubOps(SimpleMethod.java:308)

The point is that the entity field PartyContactMech.thruDate is expecting a java.sql.Timestamp while it received a java.util.Date. fine. Here the analysis of the problem

1/ At one point in time, the Now static contructor executes the code displayed below: this.converter = Converters.getConverter(Long.class, targetClass); whith targetClass set to java.sql.Timestamp

        Class<?> targetClass = null;
        try {
            if (!this.type.isEmpty()) {
                targetClass = ObjectType.loadClass(this.type);
            }
            if (targetClass == null) {
                targetClass = java.sql.Timestamp.class;
            }
            this.converter = Converters.getConverter(Long.class, targetClass);
        } catch (ClassNotFoundException e) {
            throw new ValidationException(e.getMessage(), simpleMethod, element);
        }

2/ Converters.getConverter(Long.class, java.sql.Timestamp.class); is looking at line 82 as show below in the static field convertedMap a potential converter with the following key: "java.lang.Long->java.sql.Timestamp"
OUTER:
        do {
            Converter<?, ?> result = converterMap.get(key);    // line 82
            if (result != null) {
                return UtilGenerics.cast(result);
            }
            if (noConversions.contains(key)) {
                throw new ClassNotFoundException("No converter found for " + key);
            }
            for (Converter<?, ?> value : converterMap.values()) {   // line 89
                if (value.canConvert(sourceClass, targetClass)) {    //line 90
                    converterMap.putIfAbsent(key, value);                    // line 91
                    continue OUTER;
                }
            }

3/ Under Eclipse, the converterMap.get(key) initialy does not find any key. Thus the loop line 89 starts to execute. At line 90, the value DateTimeConverter.NumberToDate.canConvert(Long.class, Timestamp .class) returns true which makes the line 91 inserting the value DateTimeConverter.NumberToDate for the key "java.lang.Long->java.sql.Timestamp"

4/ Upon restarting at the OTUER label, the statement result = compertedMap.get("java.lang.Long->java.sql.Timestamp") return DateTimeConverter.NumberToDate as result.

5/ Later on when the statement this.fieldFma.put(methodContext.getEnvMap(), this.converter.convert(System.currentTimeMillis())); from the method below executes, one gets the exception above "In entity field [PartyContactMech.thruDate] set the value passed in [java.util.Date] is not compatible w
ith the Java type of the field [java.sql.Timestamp]" because the type of the converted value is a java.util.Date and not java.sql.Timestamp.


At that point, what's make me mad is that this same code is running well when ofbiz is started with the ant start command. Thus I looked further in the analysis and the problem is coming from this fact:

The Eclipse compiler produces a DateTimeConverters.class from which the method DateTimeConverters.getClasses() returns the inner classes sorted by lexical order of their name
The Sun SDK 1.6.0_30 javac produces a DateTimeConverters.class from which the method DateTimeConverters.getClasses() returns the inner classes  sorted by the reverse lexical order of their name


Let me explain this point.

I tested with this simple program both compiler's generated classe for DateTimeConverter
public class Main {
    public static void main(String[] args) {
        DateTimeConverters dateTimeConverters;
        Class<?>[] classes = DateTimeConverters.class.getClasses();
        for (Class<?> cls : classes) {
            System.out.println(cls);
        }
    }
 Compiling the DateTimeConverter with the Eclipse compiler, the above program produces

class org.ofbiz.base.conversion.DateTimeConverters$CalendarToDate
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToLong
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToString
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$DateToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$DateToLong
class org.ofbiz.base.conversion.DateTimeConverters$DateToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$DateToString
class org.ofbiz.base.conversion.DateTimeConverters$DateToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$DurationToBigDecimal
class org.ofbiz.base.conversion.DateTimeConverters$DurationToDouble
class org.ofbiz.base.conversion.DateTimeConverters$DurationToFloat
class org.ofbiz.base.conversion.DateTimeConverters$DurationToList
class org.ofbiz.base.conversion.DateTimeConverters$DurationToLong
class org.ofbiz.base.conversion.DateTimeConverters$DurationToSet
class org.ofbiz.base.conversion.DateTimeConverters$DurationToString
class org.ofbiz.base.conversion.DateTimeConverters$GenericLocalizedConverter
class org.ofbiz.base.conversion.DateTimeConverters$LongToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$NumberToDate
class org.ofbiz.base.conversion.DateTimeConverters$NumberToDuration
class org.ofbiz.base.conversion.DateTimeConverters$NumberToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$NumberToSqlTime
class org.ofbiz.base.conversion.DateTimeConverters$NumberToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToDate
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToList
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToSet
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToString
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToTime
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToList
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToSet
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToString
class org.ofbiz.base.conversion.DateTimeConverters$StringToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$StringToDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToDuration
class org.ofbiz.base.conversion.DateTimeConverters$StringToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToSqlTime
class org.ofbiz.base.conversion.DateTimeConverters$StringToTimeZone
class org.ofbiz.base.conversion.DateTimeConverters$StringToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$TimeZoneToString
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToDate
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToList
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToSet
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToSqlDate


while compiling DateTimeConverters with the Sun SDK, the above program produces

class org.ofbiz.base.conversion.DateTimeConverters$TimeZoneToString
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToSet
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToList
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToTimeZone
class org.ofbiz.base.conversion.DateTimeConverters$StringToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$StringToSqlTime
class org.ofbiz.base.conversion.DateTimeConverters$StringToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToDuration
class org.ofbiz.base.conversion.DateTimeConverters$StringToDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToString
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToSet
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToList
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToTime
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToString
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToSet
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToList
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToDate
class org.ofbiz.base.conversion.DateTimeConverters$NumberToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$NumberToSqlTime
class org.ofbiz.base.conversion.DateTimeConverters$NumberToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$NumberToDuration
class org.ofbiz.base.conversion.DateTimeConverters$NumberToDate
class org.ofbiz.base.conversion.DateTimeConverters$LongToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$GenericLocalizedConverter
class org.ofbiz.base.conversion.DateTimeConverters$DurationToString
class org.ofbiz.base.conversion.DateTimeConverters$DurationToSet
class org.ofbiz.base.conversion.DateTimeConverters$DurationToLong
class org.ofbiz.base.conversion.DateTimeConverters$DurationToList
class org.ofbiz.base.conversion.DateTimeConverters$DurationToFloat
class org.ofbiz.base.conversion.DateTimeConverters$DurationToDouble
class org.ofbiz.base.conversion.DateTimeConverters$DurationToBigDecimal
class org.ofbiz.base.conversion.DateTimeConverters$DateToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$DateToString
class org.ofbiz.base.conversion.DateTimeConverters$DateToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$DateToLong
class org.ofbiz.base.conversion.DateTimeConverters$DateToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToString
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToLong
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToDate

Hu... How could it be that such lexical order or reverse order makes OfBiz fails or not???

Here the explanation

The Converters class initialy loads the convertedMap with this method

    public static void loadContainedConverters(Class<?> containerClass) {
        // This only returns -public- classes and interfaces
        for (Class<?> clz: containerClass.getClasses()) {
            try {
                // non-abstract, which means no interfaces or abstract classes
                if ((clz.getModifiers() & Modifier.ABSTRACT) == 0) {
                    Object value;
                    try {
                        value = clz.getConstructor().newInstance();
                    } catch (NoSuchMethodException e) {
                        // ignore this, as this class might be some other helper class,
                        // with a non-pubilc constructor
                        continue;
                    }
                    if (value instanceof ConverterLoader) {
                        ConverterLoader loader = (ConverterLoader) value;
                        loader.loadConverters();
                    }
                }
            } catch (Exception e) {
                Debug.logError(e, module);
            }
        }
    }

you can note that the main loop is driven by the statement: for (Class<?> clz: containerClass.getClasses()) which returns either the lexically ordered inner classes with Eclipse compiler or the reversed lexically ordered inner classes with the Sun SDK. This means that the convertedMap will be initialized with the same order (direct or reversed)

 Thus returning back to the Now static contructor statement which calls Converters.getConverter(Long.class, Timestamp.class), the statement convertedMap.values() will return

1/ In case of the Sun SDk, the converter DateTimeConverters$NumberToTimestamp which leads to the correct expected java type java.sql.Timestamp
2/ In case of the Eclipse compiler, the converter DateTimeConverters$NumberToDate which leads to the incorrect unexpected  java type java.util.Date.


Conclusion:
The behavior of Converters.getConverter(souceClass, targetClass) is depending of the order in which the compiler is generating the DateTimeConverters inner classes to be returned by the getClasses() method.


Proposal for solving this issue
Each time the method Class<?>.getClasses() is called, add a additional step before to sort the resulting array of inner classes in the lexically reversed order as done by the Sun SDK.


Rgds

Francis ANDRE


Reply | Threaded
Open this post in threaded view
|

Re: RFC: Serious issue with Converters.java, Sun JDK compiler and Eclipse compiler

Adrian Crum-3
This should be fixed in rev 1350081. Let me know if it works.

-Adrian

On 6/14/2012 2:21 AM, Adrian Crum wrote:
Thank you for the detailed report. I will look into it.

-Adrian

On 6/13/2012 4:27 PM, Francis ANDRE wrote:
Hi

I found a serious issue related to the order in which the method Class<?>.getClasses() returns the Class<?>[].

Let me explain the story.

First, I was running OfBiz in debug mode under Eclipse and testing the demo application, this exception raised:

2012-06-13 10:09:07,015 (http-bio-0.0.0.0-8443-exec-9) [      GenericEntity.java:426:WARN ]
---- exception report ----------------------------------------------------------
=-=-=-=-=-=-=-=-= Database type warning GenericEntity.set =-=-=-=-=-=-=-=-= In entity field [PartyContactMech.thruDate] set the value passed in [java.util.Date] is not compatible with the Java type of the field [java.sql.Timestamp]
Exception: java.lang.Exception
Message: Location of database type warning
---- stack trace ---------------------------------------------------------------
java.lang.Exception: Location of database type warning
org.ofbiz.entity.GenericEntity.set(GenericEntity.java:426)
org.ofbiz.entity.GenericEntity.put(GenericEntity.java:1418)
org.ofbiz.entity.GenericEntity.put(GenericEntity.java:1)
javax.el.MapELResolver.setValue(MapELResolver.java:286)
javax.el.CompositeELResolver.setValue(CompositeELResolver.java:329)
org.ofbiz.base.util.string.UelUtil$ExtendedCompositeResolver.setValue(UelUtil.java:337)
org.ofbiz.base.util.string.JuelConnector$ExtendedAstDot.setValue(JuelConnector.java:127)
de.odysseus.el.tree.impl.ast.AstEval.setValue(AstEval.java:87)
de.odysseus.el.TreeValueExpression.setValue(TreeValueExpression.java:146)
org.ofbiz.base.util.string.UelUtil.setValue(UelUtil.java:104)
org.ofbiz.base.util.collections.FlexibleMapAccessor.put(FlexibleMapAccessor.java:170)
org.ofbiz.minilang.method.envops.Now.exec(Now.java:100)
org.ofbiz.minilang.SimpleMethod.runSubOps(SimpleMethod.java:308)
org.ofbiz.minilang.method.conditional.CompareFieldCondition.exec(CompareFieldCondition.java:135)
org.ofbiz.minilang.SimpleMethod.runSubOps(SimpleMethod.java:308)

The point is that the entity field PartyContactMech.thruDate is expecting a java.sql.Timestamp while it received a java.util.Date. fine. Here the analysis of the problem

1/ At one point in time, the Now static contructor executes the code displayed below: this.converter = Converters.getConverter(Long.class, targetClass); whith targetClass set to java.sql.Timestamp

        Class<?> targetClass = null;
        try {
            if (!this.type.isEmpty()) {
                targetClass = ObjectType.loadClass(this.type);
            }
            if (targetClass == null) {
                targetClass = java.sql.Timestamp.class;
            }
            this.converter = Converters.getConverter(Long.class, targetClass);
        } catch (ClassNotFoundException e) {
            throw new ValidationException(e.getMessage(), simpleMethod, element);
        }

2/ Converters.getConverter(Long.class, java.sql.Timestamp.class); is looking at line 82 as show below in the static field convertedMap a potential converter with the following key: "java.lang.Long->java.sql.Timestamp"
OUTER:
        do {
            Converter<?, ?> result = converterMap.get(key);    // line 82
            if (result != null) {
                return UtilGenerics.cast(result);
            }
            if (noConversions.contains(key)) {
                throw new ClassNotFoundException("No converter found for " + key);
            }
            for (Converter<?, ?> value : converterMap.values()) {   // line 89
                if (value.canConvert(sourceClass, targetClass)) {    //line 90
                    converterMap.putIfAbsent(key, value);                    // line 91
                    continue OUTER;
                }
            }

3/ Under Eclipse, the converterMap.get(key) initialy does not find any key. Thus the loop line 89 starts to execute. At line 90, the value DateTimeConverter.NumberToDate.canConvert(Long.class, Timestamp .class) returns true which makes the line 91 inserting the value DateTimeConverter.NumberToDate for the key "java.lang.Long->java.sql.Timestamp"

4/ Upon restarting at the OTUER label, the statement result = compertedMap.get("java.lang.Long->java.sql.Timestamp") return DateTimeConverter.NumberToDate as result.

5/ Later on when the statement this.fieldFma.put(methodContext.getEnvMap(), this.converter.convert(System.currentTimeMillis())); from the method below executes, one gets the exception above "In entity field [PartyContactMech.thruDate] set the value passed in [java.util.Date] is not compatible w
ith the Java type of the field [java.sql.Timestamp]" because the type of the converted value is a java.util.Date and not java.sql.Timestamp.


At that point, what's make me mad is that this same code is running well when ofbiz is started with the ant start command. Thus I looked further in the analysis and the problem is coming from this fact:

The Eclipse compiler produces a DateTimeConverters.class from which the method DateTimeConverters.getClasses() returns the inner classes sorted by lexical order of their name
The Sun SDK 1.6.0_30 javac produces a DateTimeConverters.class from which the method DateTimeConverters.getClasses() returns the inner classes  sorted by the reverse lexical order of their name


Let me explain this point.

I tested with this simple program both compiler's generated classe for DateTimeConverter
public class Main {
    public static void main(String[] args) {
        DateTimeConverters dateTimeConverters;
        Class<?>[] classes = DateTimeConverters.class.getClasses();
        for (Class<?> cls : classes) {
            System.out.println(cls);
        }
    }
 Compiling the DateTimeConverter with the Eclipse compiler, the above program produces

class org.ofbiz.base.conversion.DateTimeConverters$CalendarToDate
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToLong
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToString
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$DateToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$DateToLong
class org.ofbiz.base.conversion.DateTimeConverters$DateToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$DateToString
class org.ofbiz.base.conversion.DateTimeConverters$DateToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$DurationToBigDecimal
class org.ofbiz.base.conversion.DateTimeConverters$DurationToDouble
class org.ofbiz.base.conversion.DateTimeConverters$DurationToFloat
class org.ofbiz.base.conversion.DateTimeConverters$DurationToList
class org.ofbiz.base.conversion.DateTimeConverters$DurationToLong
class org.ofbiz.base.conversion.DateTimeConverters$DurationToSet
class org.ofbiz.base.conversion.DateTimeConverters$DurationToString
class org.ofbiz.base.conversion.DateTimeConverters$GenericLocalizedConverter
class org.ofbiz.base.conversion.DateTimeConverters$LongToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$NumberToDate
class org.ofbiz.base.conversion.DateTimeConverters$NumberToDuration
class org.ofbiz.base.conversion.DateTimeConverters$NumberToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$NumberToSqlTime
class org.ofbiz.base.conversion.DateTimeConverters$NumberToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToDate
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToList
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToSet
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToString
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToTime
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToList
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToSet
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToString
class org.ofbiz.base.conversion.DateTimeConverters$StringToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$StringToDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToDuration
class org.ofbiz.base.conversion.DateTimeConverters$StringToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToSqlTime
class org.ofbiz.base.conversion.DateTimeConverters$StringToTimeZone
class org.ofbiz.base.conversion.DateTimeConverters$StringToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$TimeZoneToString
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToDate
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToList
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToSet
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToSqlDate


while compiling DateTimeConverters with the Sun SDK, the above program produces

class org.ofbiz.base.conversion.DateTimeConverters$TimeZoneToString
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToSet
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToList
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToTimeZone
class org.ofbiz.base.conversion.DateTimeConverters$StringToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$StringToSqlTime
class org.ofbiz.base.conversion.DateTimeConverters$StringToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToDuration
class org.ofbiz.base.conversion.DateTimeConverters$StringToDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToString
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToSet
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToList
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToTime
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToString
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToSet
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToList
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToDate
class org.ofbiz.base.conversion.DateTimeConverters$NumberToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$NumberToSqlTime
class org.ofbiz.base.conversion.DateTimeConverters$NumberToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$NumberToDuration
class org.ofbiz.base.conversion.DateTimeConverters$NumberToDate
class org.ofbiz.base.conversion.DateTimeConverters$LongToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$GenericLocalizedConverter
class org.ofbiz.base.conversion.DateTimeConverters$DurationToString
class org.ofbiz.base.conversion.DateTimeConverters$DurationToSet
class org.ofbiz.base.conversion.DateTimeConverters$DurationToLong
class org.ofbiz.base.conversion.DateTimeConverters$DurationToList
class org.ofbiz.base.conversion.DateTimeConverters$DurationToFloat
class org.ofbiz.base.conversion.DateTimeConverters$DurationToDouble
class org.ofbiz.base.conversion.DateTimeConverters$DurationToBigDecimal
class org.ofbiz.base.conversion.DateTimeConverters$DateToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$DateToString
class org.ofbiz.base.conversion.DateTimeConverters$DateToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$DateToLong
class org.ofbiz.base.conversion.DateTimeConverters$DateToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToString
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToLong
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToDate

Hu... How could it be that such lexical order or reverse order makes OfBiz fails or not???

Here the explanation

The Converters class initialy loads the convertedMap with this method

    public static void loadContainedConverters(Class<?> containerClass) {
        // This only returns -public- classes and interfaces
        for (Class<?> clz: containerClass.getClasses()) {
            try {
                // non-abstract, which means no interfaces or abstract classes
                if ((clz.getModifiers() & Modifier.ABSTRACT) == 0) {
                    Object value;
                    try {
                        value = clz.getConstructor().newInstance();
                    } catch (NoSuchMethodException e) {
                        // ignore this, as this class might be some other helper class,
                        // with a non-pubilc constructor
                        continue;
                    }
                    if (value instanceof ConverterLoader) {
                        ConverterLoader loader = (ConverterLoader) value;
                        loader.loadConverters();
                    }
                }
            } catch (Exception e) {
                Debug.logError(e, module);
            }
        }
    }

you can note that the main loop is driven by the statement: for (Class<?> clz: containerClass.getClasses()) which returns either the lexically ordered inner classes with Eclipse compiler or the reversed lexically ordered inner classes with the Sun SDK. This means that the convertedMap will be initialized with the same order (direct or reversed)

 Thus returning back to the Now static contructor statement which calls Converters.getConverter(Long.class, Timestamp.class), the statement convertedMap.values() will return

1/ In case of the Sun SDk, the converter DateTimeConverters$NumberToTimestamp which leads to the correct expected java type java.sql.Timestamp
2/ In case of the Eclipse compiler, the converter DateTimeConverters$NumberToDate which leads to the incorrect unexpected  java type java.util.Date.


Conclusion:
The behavior of Converters.getConverter(souceClass, targetClass) is depending of the order in which the compiler is generating the DateTimeConverters inner classes to be returned by the getClasses() method.


Proposal for solving this issue
Each time the method Class<?>.getClasses() is called, add a additional step before to sort the resulting array of inner classes in the lexically reversed order as done by the Sun SDK.


Rgds

Francis ANDRE


Reply | Threaded
Open this post in threaded view
|

Re: RFC: Serious issue with Converters.java, Sun JDK compiler and Eclipse compiler

Francis ANDRE
Yeap it works... verified with the latest trunk....

Thanks

Le 14/06/2012 05:34, Adrian Crum a écrit :
This should be fixed in rev 1350081. Let me know if it works.

-Adrian

On 6/14/2012 2:21 AM, Adrian Crum wrote:
Thank you for the detailed report. I will look into it.

-Adrian

On 6/13/2012 4:27 PM, Francis ANDRE wrote:
Hi

I found a serious issue related to the order in which the method Class<?>.getClasses() returns the Class<?>[].

Let me explain the story.

First, I was running OfBiz in debug mode under Eclipse and testing the demo application, this exception raised:

2012-06-13 10:09:07,015 (http-bio-0.0.0.0-8443-exec-9) [      GenericEntity.java:426:WARN ]
---- exception report ----------------------------------------------------------
=-=-=-=-=-=-=-=-= Database type warning GenericEntity.set =-=-=-=-=-=-=-=-= In entity field [PartyContactMech.thruDate] set the value passed in [java.util.Date] is not compatible with the Java type of the field [java.sql.Timestamp]
Exception: java.lang.Exception
Message: Location of database type warning
---- stack trace ---------------------------------------------------------------
java.lang.Exception: Location of database type warning
org.ofbiz.entity.GenericEntity.set(GenericEntity.java:426)
org.ofbiz.entity.GenericEntity.put(GenericEntity.java:1418)
org.ofbiz.entity.GenericEntity.put(GenericEntity.java:1)
javax.el.MapELResolver.setValue(MapELResolver.java:286)
javax.el.CompositeELResolver.setValue(CompositeELResolver.java:329)
org.ofbiz.base.util.string.UelUtil$ExtendedCompositeResolver.setValue(UelUtil.java:337)
org.ofbiz.base.util.string.JuelConnector$ExtendedAstDot.setValue(JuelConnector.java:127)
de.odysseus.el.tree.impl.ast.AstEval.setValue(AstEval.java:87)
de.odysseus.el.TreeValueExpression.setValue(TreeValueExpression.java:146)
org.ofbiz.base.util.string.UelUtil.setValue(UelUtil.java:104)
org.ofbiz.base.util.collections.FlexibleMapAccessor.put(FlexibleMapAccessor.java:170)
org.ofbiz.minilang.method.envops.Now.exec(Now.java:100)
org.ofbiz.minilang.SimpleMethod.runSubOps(SimpleMethod.java:308)
org.ofbiz.minilang.method.conditional.CompareFieldCondition.exec(CompareFieldCondition.java:135)
org.ofbiz.minilang.SimpleMethod.runSubOps(SimpleMethod.java:308)

The point is that the entity field PartyContactMech.thruDate is expecting a java.sql.Timestamp while it received a java.util.Date. fine. Here the analysis of the problem

1/ At one point in time, the Now static contructor executes the code displayed below: this.converter = Converters.getConverter(Long.class, targetClass); whith targetClass set to java.sql.Timestamp

        Class<?> targetClass = null;
        try {
            if (!this.type.isEmpty()) {
                targetClass = ObjectType.loadClass(this.type);
            }
            if (targetClass == null) {
                targetClass = java.sql.Timestamp.class;
            }
            this.converter = Converters.getConverter(Long.class, targetClass);
        } catch (ClassNotFoundException e) {
            throw new ValidationException(e.getMessage(), simpleMethod, element);
        }

2/ Converters.getConverter(Long.class, java.sql.Timestamp.class); is looking at line 82 as show below in the static field convertedMap a potential converter with the following key: "java.lang.Long->java.sql.Timestamp"
OUTER:
        do {
            Converter<?, ?> result = converterMap.get(key);    // line 82
            if (result != null) {
                return UtilGenerics.cast(result);
            }
            if (noConversions.contains(key)) {
                throw new ClassNotFoundException("No converter found for " + key);
            }
            for (Converter<?, ?> value : converterMap.values()) {   // line 89
                if (value.canConvert(sourceClass, targetClass)) {    //line 90
                    converterMap.putIfAbsent(key, value);                    // line 91
                    continue OUTER;
                }
            }

3/ Under Eclipse, the converterMap.get(key) initialy does not find any key. Thus the loop line 89 starts to execute. At line 90, the value DateTimeConverter.NumberToDate.canConvert(Long.class, Timestamp .class) returns true which makes the line 91 inserting the value DateTimeConverter.NumberToDate for the key "java.lang.Long->java.sql.Timestamp"

4/ Upon restarting at the OTUER label, the statement result = compertedMap.get("java.lang.Long->java.sql.Timestamp") return DateTimeConverter.NumberToDate as result.

5/ Later on when the statement this.fieldFma.put(methodContext.getEnvMap(), this.converter.convert(System.currentTimeMillis())); from the method below executes, one gets the exception above "In entity field [PartyContactMech.thruDate] set the value passed in [java.util.Date] is not compatible w
ith the Java type of the field [java.sql.Timestamp]" because the type of the converted value is a java.util.Date and not java.sql.Timestamp.


At that point, what's make me mad is that this same code is running well when ofbiz is started with the ant start command. Thus I looked further in the analysis and the problem is coming from this fact:

The Eclipse compiler produces a DateTimeConverters.class from which the method DateTimeConverters.getClasses() returns the inner classes sorted by lexical order of their name
The Sun SDK 1.6.0_30 javac produces a DateTimeConverters.class from which the method DateTimeConverters.getClasses() returns the inner classes  sorted by the reverse lexical order of their name


Let me explain this point.

I tested with this simple program both compiler's generated classe for DateTimeConverter
public class Main {
    public static void main(String[] args) {
        DateTimeConverters dateTimeConverters;
        Class<?>[] classes = DateTimeConverters.class.getClasses();
        for (Class<?> cls : classes) {
            System.out.println(cls);
        }
    }
 Compiling the DateTimeConverter with the Eclipse compiler, the above program produces

class org.ofbiz.base.conversion.DateTimeConverters$CalendarToDate
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToLong
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToString
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$DateToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$DateToLong
class org.ofbiz.base.conversion.DateTimeConverters$DateToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$DateToString
class org.ofbiz.base.conversion.DateTimeConverters$DateToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$DurationToBigDecimal
class org.ofbiz.base.conversion.DateTimeConverters$DurationToDouble
class org.ofbiz.base.conversion.DateTimeConverters$DurationToFloat
class org.ofbiz.base.conversion.DateTimeConverters$DurationToList
class org.ofbiz.base.conversion.DateTimeConverters$DurationToLong
class org.ofbiz.base.conversion.DateTimeConverters$DurationToSet
class org.ofbiz.base.conversion.DateTimeConverters$DurationToString
class org.ofbiz.base.conversion.DateTimeConverters$GenericLocalizedConverter
class org.ofbiz.base.conversion.DateTimeConverters$LongToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$NumberToDate
class org.ofbiz.base.conversion.DateTimeConverters$NumberToDuration
class org.ofbiz.base.conversion.DateTimeConverters$NumberToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$NumberToSqlTime
class org.ofbiz.base.conversion.DateTimeConverters$NumberToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToDate
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToList
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToSet
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToString
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToTime
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToList
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToSet
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToString
class org.ofbiz.base.conversion.DateTimeConverters$StringToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$StringToDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToDuration
class org.ofbiz.base.conversion.DateTimeConverters$StringToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToSqlTime
class org.ofbiz.base.conversion.DateTimeConverters$StringToTimeZone
class org.ofbiz.base.conversion.DateTimeConverters$StringToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$TimeZoneToString
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToDate
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToList
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToSet
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToSqlDate


while compiling DateTimeConverters with the Sun SDK, the above program produces

class org.ofbiz.base.conversion.DateTimeConverters$TimeZoneToString
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToSet
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToList
class org.ofbiz.base.conversion.DateTimeConverters$TimestampToDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToTimeZone
class org.ofbiz.base.conversion.DateTimeConverters$StringToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$StringToSqlTime
class org.ofbiz.base.conversion.DateTimeConverters$StringToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToDuration
class org.ofbiz.base.conversion.DateTimeConverters$StringToDate
class org.ofbiz.base.conversion.DateTimeConverters$StringToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToString
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToSet
class org.ofbiz.base.conversion.DateTimeConverters$SqlTimeToList
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToTime
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToString
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToSet
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToList
class org.ofbiz.base.conversion.DateTimeConverters$SqlDateToDate
class org.ofbiz.base.conversion.DateTimeConverters$NumberToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$NumberToSqlTime
class org.ofbiz.base.conversion.DateTimeConverters$NumberToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$NumberToDuration
class org.ofbiz.base.conversion.DateTimeConverters$NumberToDate
class org.ofbiz.base.conversion.DateTimeConverters$LongToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$GenericLocalizedConverter
class org.ofbiz.base.conversion.DateTimeConverters$DurationToString
class org.ofbiz.base.conversion.DateTimeConverters$DurationToSet
class org.ofbiz.base.conversion.DateTimeConverters$DurationToLong
class org.ofbiz.base.conversion.DateTimeConverters$DurationToList
class org.ofbiz.base.conversion.DateTimeConverters$DurationToFloat
class org.ofbiz.base.conversion.DateTimeConverters$DurationToDouble
class org.ofbiz.base.conversion.DateTimeConverters$DurationToBigDecimal
class org.ofbiz.base.conversion.DateTimeConverters$DateToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$DateToString
class org.ofbiz.base.conversion.DateTimeConverters$DateToSqlDate
class org.ofbiz.base.conversion.DateTimeConverters$DateToLong
class org.ofbiz.base.conversion.DateTimeConverters$DateToCalendar
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToTimestamp
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToString
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToLong
class org.ofbiz.base.conversion.DateTimeConverters$CalendarToDate

Hu... How could it be that such lexical order or reverse order makes OfBiz fails or not???

Here the explanation

The Converters class initialy loads the convertedMap with this method

    public static void loadContainedConverters(Class<?> containerClass) {
        // This only returns -public- classes and interfaces
        for (Class<?> clz: containerClass.getClasses()) {
            try {
                // non-abstract, which means no interfaces or abstract classes
                if ((clz.getModifiers() & Modifier.ABSTRACT) == 0) {
                    Object value;
                    try {
                        value = clz.getConstructor().newInstance();
                    } catch (NoSuchMethodException e) {
                        // ignore this, as this class might be some other helper class,
                        // with a non-pubilc constructor
                        continue;
                    }
                    if (value instanceof ConverterLoader) {
                        ConverterLoader loader = (ConverterLoader) value;
                        loader.loadConverters();
                    }
                }
            } catch (Exception e) {
                Debug.logError(e, module);
            }
        }
    }

you can note that the main loop is driven by the statement: for (Class<?> clz: containerClass.getClasses()) which returns either the lexically ordered inner classes with Eclipse compiler or the reversed lexically ordered inner classes with the Sun SDK. This means that the convertedMap will be initialized with the same order (direct or reversed)

 Thus returning back to the Now static contructor statement which calls Converters.getConverter(Long.class, Timestamp.class), the statement convertedMap.values() will return

1/ In case of the Sun SDk, the converter DateTimeConverters$NumberToTimestamp which leads to the correct expected java type java.sql.Timestamp
2/ In case of the Eclipse compiler, the converter DateTimeConverters$NumberToDate which leads to the incorrect unexpected  java type java.util.Date.


Conclusion:
The behavior of Converters.getConverter(souceClass, targetClass) is depending of the order in which the compiler is generating the DateTimeConverters inner classes to be returned by the getClasses() method.


Proposal for solving this issue
Each time the method Class<?>.getClasses() is called, add a additional step before to sort the resulting array of inner classes in the lexically reversed order as done by the Sun SDK.


Rgds

Francis ANDRE