JDK-6587525 : ClassCastException needs "origin" and "target" attributes
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 7
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2007-07-31
  • Updated: 2010-11-17
  • Resolved: 2010-11-17
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
A DESCRIPTION OF THE REQUEST :
Now composing CCE detail message is completely up to code that creates (and throws) CCE. This lead to code duplication since most of messages look alike (i.e. "<origin class> cannot be cast to <target class>"). This RFE is about adding facility to CCE to compose uniform detail message by two classes (e.g. add new constructor that takes two classes as parameters)

Another problem is that "<origin class> cannot be cast to <target class>" sometimes is not helpful enough. CCE will appear if instance of one class will be casted to class with the same name but loaded by another classloader. In this case message should provide more information: "<origin class> is/extends/implements <target class>, which is not loaded by required classloader". Or something like this.

Also CCE should have two readonly attributes: "origin" and "target". Using these attributes outer-most exception handler of application may dump classloader hierarchy for origin and target classes in order to help to diagnose the problem more precisely (i.e. more than CCE detail message does).

Related bugs:
(reflect) Class.cast(Object) throws CCE without detail message
	http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6456938
Class.cast exception detail construction should be refactored
	http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6586569

Here is example how ClassCastException may look

public
class ClassCastException extends RuntimeException {
    private final Class<?> origin;
    private final Class<?> target;

    /**
     * Constructs a <code>ClassCastException</code> with no detail message.
     */
    public ClassCastException() {
	this(null, null, null);
    }

    /**
     * Constructs a <code>ClassCastException</code> with the specified
     * detail message.
     *
     * @param   s   the detail message.
     */
    public ClassCastException(String s) {
	this(s, null, null);
    }

    public ClassCastException(String s, Class<?> origin, Class<?> target) {
        super(s);
        this.origin = origin;
        this.target = target;
    }

    public ClassCastException(Class<?> origin, Class<?> target) {
        this(null, origin, target);
    }

    public Class<?> getOrigin() {
        return origin;
    }

    public Class<?> getTarget() {
        return target;
    }

    public String getMessage() {
        String msg = super.getMessage();
        if (msg != null || origin == null || target == null) {
            // we return existing 'detail message' if it is already
            // set by client or if either 'origin' or 'target' is missing.
            return msg;
        }
        // ... otherwise we compose uniform descriptive 'detail message'
        // taking into account classloader issues.
        Class<?> ancestor = findAncestorByName(origin, target.getName());
        if (ancestor != null && ancestor.getClassLoader() != target.getClassLoader()) {
            return origin + " is/extends/implements " + target + ", which is not loaded by required classloader";
        } else {
            // if it happens that ancestor.getClassLoader() == target.getClassLoader()
            // we just fall back on standard message.
            return origin + " cannot be cast to " + target;
        }
    }

    static Class<?> findAncestorByName(Class<?> origin, String name) {
        if (name.equals(origin.getName()))
            return origin;
        Class<?> result = null;
        Class<?> sup = origin.getSuperclass();
        if (sup != null)
            result = findAncestorByName(sup, name);
        if (result == null) {
            for (Class<?> c : origin.getInterfaces()) {
                result = findAncestorByName(c, name);
                if (result != null)
                    break;
            }
        }
        return result;
    }

}


JUSTIFICATION :
It let's avoid duplication of code that constructs CCE detail message and make this message more helpful.

Comments
EVALUATION Duplicate of 5069708.
18-08-2008