Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » OCL » ClassCastException thrown when using ecore::EDouble
ClassCastException thrown when using ecore::EDouble [message #1067896] Thu, 11 July 2013 03:36 Go to next message
Cedric Moonen is currently offline Cedric Moonen
Messages: 269
Registered: August 2009
Senior Member
Hi Ed,

I have a very simple ecore model (the full project with the genmodel is in attachment too):

import ecore : 'http://www.eclipse.org/emf/2002/Ecore#/';

package components : components = 'http://components/1.0'
{
	class Container
	{
		attribute requiredWeight : ecore::EDouble;
		attribute actualWeight : ecore::EDouble { derived readonly transient volatile }
		{
			derivation: components.weight
					->sum();
		}
		
		property components#parentContainer : Component[*] { ordered composes };
		
		invariant validWeight('The actual weight exceeds the required weight'): if actualWeight > requiredWeight
				then null
				else true
				endif;
		
	}
	
	class Component
	{
		property parentContainer#components : Container;
		attribute weight : ecore::EDouble;
	}	
	
}


When I generate Java code for this example, I see that the generated getActualWeight method of the Container class looks like this:

	public double getActualWeight() {
		/**
		 * components.weight->sum()
		 */
		final /*@NonNull*/ /*@NonInvalid*/ components.Container self = this;
		final /*@NonNull*/ /*@NonInvalid*/ DomainEvaluator evaluator = new EcoreExecutorManager(this, ComponentsTables.LIBRARY);
		final /*@NonNull*/ /*@NonInvalid*/ IdResolver idResolver = evaluator.getIdResolver();
		final /*@NonNull*/ /*@Thrown*/ List<?> components = self.getComponents();
		final /*@NonNull*/ /*@Thrown*/ OrderedSetValue BOXED_components = idResolver.createOrderedSetOfAll(ComponentsTables.ORD_CLSSid_Component, components);
		/*@NonNull*/ /*@NonInvalid*/ SequenceValue.Accumulator accumulator = ValuesUtil.createSequenceAccumulatorValue(ComponentsTables.SEQ_PRIMid_Real);
		/*@Nullable*/ Iterator<?> ITERATOR__1 = BOXED_components.iterator();
		/*@NonNull*/ /*@Thrown*/ SequenceValue collect;
		while (true) {
		    if (!ITERATOR__1.hasNext()) {
		        collect = accumulator;
		        break;
		    }
		    /*@Nullable*/ /*@NonInvalid*/ Component _1 = (Component)ITERATOR__1.next();
		    /**
		     * weight
		     */
		    if (_1 == null) {
		        throw new InvalidValueException("Null source");
		    }
		    final /*@NonNull*/ /*@Thrown*/ Number weight = _1.getWeight();
		    final /*@NonNull*/ /*@Thrown*/ RealValue BOXED_weight = ValuesUtil.realValueOf(weight);
		    //
		    accumulator.add(BOXED_weight);
		}
		final /*@NonNull*/ /*@Thrown*/ RealValue sum = (RealValue)CollectionSumOperation.INSTANCE.evaluate(evaluator, TypeId.REAL, collect);
		final /*@NonNull*/ /*@Thrown*/ Number UNBOXED_sum = sum.asNumber();
		return (Double)UNBOXED_sum;
	}


The last line is wrong (the cast) and will produce a ClassCastException when an instance of the model is validated (or when the property view is retrieving the value of actualWeight, but this is internally ignored, instead the value is simply not visible). This problem also occurs when generating Delegates instead of Java code for OCL constraints.

The last line should in fact be:
return UNBOXED_sum.doubleValue();


I have some other code which is similar (a method body which is also supposed to return an ecore::EDouble) for which this is generated properly, so I think this is very specific to the scenario that I'm having here.

Any idea what might cause the problem ?
Thanks,
Cédric
Re: ClassCastException thrown when using ecore::EDouble [message #1067910 is a reply to message #1067896] Thu, 11 July 2013 04:34 Go to previous messageGo to next message
Ed Willink is currently offline Ed Willink
Messages: 3844
Registered: July 2009
Senior Member
Hi

When you have such a good repro, please raise a Bugzilla.

Regards

Ed Willink

On 11/07/2013 08:36, Cedric Moonen wrote:
> Hi Ed,
>
> I have a very simple ecore model (the full project with the genmodel is in attachment too):
>
> import ecore : 'http://www.eclipse.org/emf/2002/Ecore#/';
>
> package components : components = 'http://components/1.0'
> {
> class Container
> {
> attribute requiredWeight : ecore::EDouble;
> attribute actualWeight : ecore::EDouble { derived readonly transient volatile }
> {
> derivation: components.weight
> ->sum();
> }
>
> property components#parentContainer : Component[*] { ordered composes };
>
> invariant validWeight('The actual weight exceeds the required weight'): if actualWeight> requiredWeight
> then null
> else true
> endif;
>
> }
>
> class Component
> {
> property parentContainer#components : Container;
> attribute weight : ecore::EDouble;
> }
>
> }
>
> When I generate Java code for this example, I see that the generated getActualWeight method of the Container class looks like this:
>
> public double getActualWeight() {
> /**
> * components.weight->sum()
> */
> final /*@NonNull*/ /*@NonInvalid*/ components.Container self = this;
> final /*@NonNull*/ /*@NonInvalid*/ DomainEvaluator evaluator = new EcoreExecutorManager(this, ComponentsTables.LIBRARY);
> final /*@NonNull*/ /*@NonInvalid*/ IdResolver idResolver = evaluator.getIdResolver();
> final /*@NonNull*/ /*@Thrown*/ List<?> components = self.getComponents();
> final /*@NonNull*/ /*@Thrown*/ OrderedSetValue BOXED_components = idResolver.createOrderedSetOfAll(ComponentsTables.ORD_CLSSid_Component, components);
> /*@NonNull*/ /*@NonInvalid*/ SequenceValue.Accumulator accumulator = ValuesUtil.createSequenceAccumulatorValue(ComponentsTables.SEQ_PRIMid_Real);
> /*@Nullable*/ Iterator<?> ITERATOR__1 = BOXED_components.iterator();
> /*@NonNull*/ /*@Thrown*/ SequenceValue collect;
> while (true) {
> if (!ITERATOR__1.hasNext()) {
> collect = accumulator;
> break;
> }
> /*@Nullable*/ /*@NonInvalid*/ Component _1 = (Component)ITERATOR__1.next();
> /**
> * weight
> */
> if (_1 == null) {
> throw new InvalidValueException("Null source");
> }
> final /*@NonNull*/ /*@Thrown*/ Number weight = _1.getWeight();
> final /*@NonNull*/ /*@Thrown*/ RealValue BOXED_weight = ValuesUtil.realValueOf(weight);
> //
> accumulator.add(BOXED_weight);
> }
> final /*@NonNull*/ /*@Thrown*/ RealValue sum = (RealValue)CollectionSumOperation.INSTANCE.evaluate(evaluator, TypeId.REAL, collect);
> final /*@NonNull*/ /*@Thrown*/ Number UNBOXED_sum = sum.asNumber();
> return (Double)UNBOXED_sum;
> }
>
> The last line is wrong (the cast) and will produce a ClassCastException when an instance of the model is validated (or when the property view is retrieving the value of actualWeight, but this is internally ignored, instead the value is simply not visible). This problem also occurs when generating Delegates instead of Java code for OCL constraints.
>
> The last line should in fact be:
> return UNBOXED_sum.doubleValue();
>
> I have some other code which is similar (a method body which is also supposed to return an ecore::EDouble) for which this is generated properly, so I think this is very specific to the scenario that I'm having here.
>
> Any idea what might cause the problem ?
> Thanks,
> Cédric
Re: ClassCastException thrown when using ecore::EDouble [message #1067923 is a reply to message #1067910] Thu, 11 July 2013 05:16 Go to previous message
Cedric Moonen is currently offline Cedric Moonen
Messages: 269
Registered: August 2009
Senior Member
Ok done: https://bugs.eclipse.org/bugs/show_bug.cgi?id=412736
Previous Topic:Debugging OCL constraints via java debugger
Next Topic:How to get OCL variable from Java code
Goto Forum:
  


Current Time: Sun Apr 20 18:11:44 EDT 2014

Powered by FUDForum. Page generated in 0.01611 seconds