eclipse-xtext / eclipse-xtext/xtext

XbaseInterpreter.java:_doEvaluate(XCastedExpression - `throw new EvaluationException(new ClassCastException(typeName))` - not enough information to show to the user what cannot be casted to what

Open
#3,595 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
831
Forks
330
Avg merge
3d 7h
Merged PRs (30d)
12

Description

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 https://github.com/openhab/openhab-core/issues/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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with XbaseInterpreter.java at _doEvaluate(XCastedExpression, IEvaluationContext, CancelIndicator) and compare its ClassCastException handling with Java's message. Read openHAB's ScriptInterpreter.xtend usage and openHAB issue 5323 to understand the dangers of re-evaluating the target expression. Done means the resulting evaluation error identifies both source and target types without relying on a second evaluation.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.