class A {
public static void main(String[] arg) {
try {
Object x = Integer.valueOf(0);
System.out.println("A" + (String)x);
} catch (ClassCastException e) {
System.out.println(e.getMessage());
}
}
}
produces with Java 21
$ java A.java
class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
That is: ClassCastException.getMessage() is expected to spell both source and target classes of casting.
When XbaseInterpreter.java:protected Object _doEvaluate(XCastedExpression castedExpression, IEvaluationContext, CancelIndicator) creates a ClassCastException, it puts as detailed message the typeName - the target type.
To print a casting error to the user, containing both source and target classes of casting, one has in a derived class to:
override Object _doEvaluate(XCastedExpression castedExpression, IEvaluationContext context, CancelIndicator indicator) {
try {
return super._doEvaluate(castedExpression, context, indicator)
} catch (RuntimeException e) {
if (e.cause instanceof ClassCastException) {
and then constructs a message, containing both source and target types of the casting. Obtaining the target type is easy, it is a matter of calling castedExpression.getType().getType().getQualifiedName(). In fact this is the value of the parameter passed to the constructor of ClassCastException in XbaseInterpreter.java:_doEvaluate(XCastedExpression, IEvaluationContext, CancelIndicator).
However there is no way to know, when the EvaluationException(new ClassCastException()) is catched, what was the source type of the expression: In a as B the class of a.
In openHAB to get the source type is re-executed val Object result = internalEvaluate(castedExpression.getTarget(), context, indicator);. The problem is that calling once val Object result = internalEvaluate(castedExpression.getTarget(), context, indicator); in the super class, and calling again val Object result = internalEvaluate(castedExpression.getTarget(), context, indicator); in the derived class might not necessary have the same result: states might have changed in the meantime, so that re-evaluating the same expression, for the sake of logging an error, might produce no more errors. This in fact does happen, as described at openhab/openhab-core#5323 .
That said in
protected Object _doEvaluate(XCastedExpression castedExpression, IEvaluationContext context, CancelIndic
ator indicator) {
…
try {
expectedType.cast(result);
} catch (ClassCastException e) {
throw new EvaluationException(new ClassCastException(typeName));
}
- spell in the ClassCastException constructor parameter as sentence the target and source types of the casting, as java does in the example of the beginning, or
- instead of passing the target class name (which can be implied when overriding the method by calling
castedExpression.getType().getType().getQualifiedName() , pass the name of the source class.
In both cases the aim is to present to the user a message telling what cannot be casted to what, and currently this is not possible.
produces with Java 21
That is: ClassCastException.getMessage() is expected to spell both source and target classes of casting.
When
XbaseInterpreter.java:protected Object _doEvaluate(XCastedExpression castedExpression, IEvaluationContext, CancelIndicator)creates a ClassCastException, it puts as detailed message thetypeName- the target type.To print a casting error to the user, containing both source and target classes of casting, one has in a derived class to:
and then constructs a message, containing both source and target types of the casting. Obtaining the target type is easy, it is a matter of calling
castedExpression.getType().getType().getQualifiedName(). In fact this is the value of the parameter passed to the constructor ofClassCastExceptionin XbaseInterpreter.java:_doEvaluate(XCastedExpression, IEvaluationContext, CancelIndicator).However there is no way to know, when the
EvaluationException(new ClassCastException())is catched, what was the source type of the expression: Ina as Bthe class ofa.In openHAB to get the source type is re-executed
val Object result = internalEvaluate(castedExpression.getTarget(), context, indicator);. The problem is that calling onceval Object result = internalEvaluate(castedExpression.getTarget(), context, indicator);in the super class, and calling againval Object result = internalEvaluate(castedExpression.getTarget(), context, indicator);in the derived class might not necessary have the same result: states might have changed in the meantime, so that re-evaluating the same expression, for the sake of logging an error, might produce no more errors. This in fact does happen, as described at openhab/openhab-core#5323 .That said in
castedExpression.getType().getType().getQualifiedName(), pass the name of the source class.In both cases the aim is to present to the user a message telling what cannot be casted to what, and currently this is not possible.