Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6587525

ClassCastException needs "origin" and "target" attributes

    Details

    • Type: Enhancement
    • Status: Closed
    • Priority: P3
    • Resolution: Duplicate
    • Affects Version/s: 7
    • Fix Version/s: None
    • Component/s: core-libs
    • Labels:
    • Subcomponent:
    • CPU:
      x86
    • OS:
      windows_xp

      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.

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                Unassigned
                Reporter:
                ryeung Roger Yeung (Inactive)
              • Votes:
                0 Vote for this issue
                Watchers:
                1 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:
                  Imported:
                  Indexed: