Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » EMF » EObject#eSet and autoboxing
EObject#eSet and autoboxing [message #652229] Thu, 03 February 2011 09:37 Go to next message
Thomas Schindl is currently offline Thomas SchindlFriend
Messages: 6505
Registered: July 2009
Senior Member
Hi,

I've been run into troubles using eSet, primitive values and autoboxing
(in conjunction with databinding where I was able to fix the problem).

Suppose you have the following feature:

-----------8<-----------
private long myLongFeature;

public void setMyLongFeature(long myLongFeature) {
// ...
}

public void eSet(int featureID, Object newValue) {
switch (featureID) {
//
setMyLongFeature((Long)newValue);
}
}
-----------8<-----------

Now the problem is that when databinding under certain circumstances
converts a String to a number it can happen that the eSet-Method is
called with an int-value which results in ClassCastException because an
int is converted to Integer and the cast above fails.

My question now is would it be better if we'd make the eSet get
generated like this:

-----------8<-----------
public void eSet(int featureID, Object newValue) {
switch (featureID) {
//
setMyLongFeature(((Number)newValue).longValue());
}
}
-----------8<-----------

My understanding of autoboxing is that this is more or less what the
compiler makes from setMyLongFeature((Long)newValue) anyways because at
the bytecode level you'll get something like this:

-----------8<-----------
setMyLongFeature(((Long)newValue).longValue());
-----------8<-----------

This way a call to myinstance.eSet(MY_LONG_FEATURE,10) works like
myinstance.setMyLongFeature(10).

So my suggestion would be to make the eSet-code behave like statically
typed Java method calls in terms of primitive conversion (for types like
long/double this is as easy as shown above) for other types the
primitive conversion rules have be taken into account.

Tom
Re: EObject#eSet and autoboxing [message #652254 is a reply to message #652229] Thu, 03 February 2011 10:36 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 30545
Registered: July 2009
Senior Member
Tom,

Comments below.


Tom Schindl wrote:
> Hi,
>
> I've been run into troubles using eSet, primitive values and autoboxing
> (in conjunction with databinding where I was able to fix the problem).
>
> Suppose you have the following feature:
>
> -----------8<-----------
> private long myLongFeature;
>
> public void setMyLongFeature(long myLongFeature) {
> // ...
> }
>
> public void eSet(int featureID, Object newValue) {
> switch (featureID) {
> //
> setMyLongFeature((Long)newValue);
> }
> }
> -----------8<-----------
>
> Now the problem is that when databinding under certain circumstances
> converts a String to a number it can happen that the eSet-Method is
> called with an int-value which results in ClassCastException because an
> int is converted to Integer and the cast above fails.
>
As it should...
> My question now is would it be better if we'd make the eSet get
> generated like this:
>
> -----------8<-----------
> public void eSet(int featureID, Object newValue) {
> switch (featureID) {
> //
> setMyLongFeature(((Number)newValue).longValue());
> }
> }
>
It's never been the intention for eSet to do any kind of type
conversion. In the case of int you'd do the same, and if you passed a
long that was too big, it would just truncate the value...
> -----------8<-----------
>
> My understanding of autoboxing is that this is more or less what the
> compiler makes from setMyLongFeature((Long)newValue) anyways because at
> the bytecode level you'll get something like this:
>
> -----------8<-----------
> setMyLongFeature(((Long)newValue).longValue());
> -----------8<-----------
>
> This way a call to myinstance.eSet(MY_LONG_FEATURE,10) works like
> myinstance.setMyLongFeature(10).
>
> So my suggestion would be to make the eSet-code behave like statically
> typed Java method calls in terms of primitive conversion (for types like
> long/double this is as easy as shown above) for other types the
> primitive conversion rules have be taken into account.
>
I don't think this is a great idea. It makes all numbers
interchangeable in any direction, some of them lossy. That's just not
the intent...
> Tom
>
Re: EObject#eSet and autoboxing [message #652256 is a reply to message #652254] Thu, 03 February 2011 11:06 Go to previous messageGo to next message
Thomas Schindl is currently offline Thomas SchindlFriend
Messages: 6505
Registered: July 2009
Senior Member
[...]
> It's never been the intention for eSet to do any kind of type
> conversion. In the case of int you'd do the same, and if you passed a
> long that was too big, it would just truncate the value...

Is it really a conversion when we talk about primitives? Isn't every int
a long - so to any method I can pass a long I'm free to pass an int,
short, char, byte?

>> -----------8<-----------
>>
>> My understanding of autoboxing is that this is more or less what the
>> compiler makes from setMyLongFeature((Long)newValue) anyways because at
>> the bytecode level you'll get something like this:
>>
>> -----------8<-----------
>> setMyLongFeature(((Long)newValue).longValue());
>> -----------8<-----------
>>
>> This way a call to myinstance.eSet(MY_LONG_FEATURE,10) works like
>> myinstance.setMyLongFeature(10).
>>
>> So my suggestion would be to make the eSet-code behave like statically
>> typed Java method calls in terms of primitive conversion (for types like
>> long/double this is as easy as shown above) for other types the
>> primitive conversion rules have be taken into account.
>>
> I don't think this is a great idea. It makes all numbers
> interchangeable in any direction, some of them lossy. That's just not
> the intent...

This is certainly NOT true for double/long as you wrote "some of them
lossy".

Would it change your opinion when I tell you that Java-Reflection does
what I request here?

> import java.lang.reflect.Method;
>
> public class TestReflection {
>
> public static void setLong(long l) {
> System.err.println("Long: " + l);
> }
>
> public static void setInt(int i) {
> System.err.println("Integer: " + i);
> }
>
> public static void setShort(short s) {
> System.err.println("Short: " + s);
> }
>
> public static void setDouble(double i) {
> System.err.println("Double: " + i);
> }
>
> /**
> * @param args
> */
> public static void main(String[] args) {
> // TODO Auto-generated method stub
> try {
> Method m = TestReflection.class.getMethod("setLong", new Class[] { long.class });
> m.invoke(null, new Object[] { 10 } );
>
> m = TestReflection.class.getMethod("setDouble", new Class[] { double.class });
> m.invoke(null, new Object[] { 10 } );
>
> m = TestReflection.class.getMethod("setDouble", new Class[] { double.class });
> m.invoke(null, new Object[] { 10L } );
>
> m = TestReflection.class.getMethod("setDouble", new Class[] { double.class });
> m.invoke(null, new Object[] { 10f } );
>
> //WILL FAIL m = TestReflection.class.getMethod("setInt", new Class[] { int.class });
> // m.invoke(null, new Object[] { 10L } );
>
> //WILL FAIL m = TestReflection.class.getMethod("setShort", new Class[] { short.class });
> // m.invoke(null, new Object[] { 10 } );
> } catch (Exception e) {
> // TODO Auto-generated catch block
> e.printStackTrace();
> }
> }
>
> }

So it looks like Java-Reflection has certain rules when it comes to
primitive types when called reflectively.

To a method with:
* double: you can pass Double,Float,Long,Integer,Short,Character,Byte
* float: you can pass Float,Integer
* long: you can pass Long,Integer,Short,Character,Byte
* ...

Tom
Re: EObject#eSet and autoboxing [message #652418 is a reply to message #652256] Thu, 03 February 2011 19:48 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 30545
Registered: July 2009
Senior Member
This is a multi-part message in MIME format.
--------------000000080702080309020700
Content-Type: text/plain; charset=ISO-8859-15; format=flowed
Content-Transfer-Encoding: 7bit

Tom,

Comments below.

Tom Schindl wrote:
> [...]
>
>> It's never been the intention for eSet to do any kind of type
>> conversion. In the case of int you'd do the same, and if you passed a
>> long that was too big, it would just truncate the value...
>>
>
> Is it really a conversion when we talk about primitives? Isn't every int
> a long - so to any method I can pass a long I'm free to pass an int,
> short, char, byte?
>
Well of course the issue is, how does this generalize?
>
>>> -----------8<-----------
>>>
>>> My understanding of autoboxing is that this is more or less what the
>>> compiler makes from setMyLongFeature((Long)newValue) anyways because at
>>> the bytecode level you'll get something like this:
>>>
>>> -----------8<-----------
>>> setMyLongFeature(((Long)newValue).longValue());
>>> -----------8<-----------
>>>
>>> This way a call to myinstance.eSet(MY_LONG_FEATURE,10) works like
>>> myinstance.setMyLongFeature(10).
>>>
>>> So my suggestion would be to make the eSet-code behave like statically
>>> typed Java method calls in terms of primitive conversion (for types like
>>> long/double this is as easy as shown above) for other types the
>>> primitive conversion rules have be taken into account.
>>>
>>>
>> I don't think this is a great idea. It makes all numbers
>> interchangeable in any direction, some of them lossy. That's just not
>> the intent...
>>
>
> This is certainly NOT true for double/long as you wrote "some of them
> lossy".
>
Actually it's is true for Double->Long.
> Would it change your opinion when I tell you that Java-Reflection does
> what I request here?
>
Not necessarily. Complexity is something that is often best avoided.
So something that's not been an issue for almost 10 years might be
better off left as is.
>
>> import java.lang.reflect.Method;
>>
>> public class TestReflection {
>>
>> public static void setLong(long l) {
>> System.err.println("Long: " + l);
>> }
>>
>> public static void setInt(int i) {
>> System.err.println("Integer: " + i);
>> }
>>
>> public static void setShort(short s) {
>> System.err.println("Short: " + s);
>> }
>>
>> public static void setDouble(double i) {
>> System.err.println("Double: " + i);
>> }
>>
>> /**
>> * @param args
>> */
>> public static void main(String[] args) {
>> // TODO Auto-generated method stub
>> try {
>> Method m = TestReflection.class.getMethod("setLong", new Class[] { long.class });
>> m.invoke(null, new Object[] { 10 } );
>>
>> m = TestReflection.class.getMethod("setDouble", new Class[] { double.class });
>> m.invoke(null, new Object[] { 10 } );
>>
>> m = TestReflection.class.getMethod("setDouble", new Class[] { double.class });
>> m.invoke(null, new Object[] { 10L } );
>>
>> m = TestReflection.class.getMethod("setDouble", new Class[] { double.class });
>> m.invoke(null, new Object[] { 10f } );
>>
>> //WILL FAIL m = TestReflection.class.getMethod("setInt", new Class[] { int.class });
>> // m.invoke(null, new Object[] { 10L } );
>>
>> //WILL FAIL m = TestReflection.class.getMethod("setShort", new Class[] { short.class });
>> // m.invoke(null, new Object[] { 10 } );
>> } catch (Exception e) {
>> // TODO Auto-generated catch block
>> e.printStackTrace();
>> }
>> }
>>
>> }
>>
>
> So it looks like Java-Reflection has certain rules when it comes to
> primitive types when called reflectively.
>
I guess the question is, what are the rules?
> To a method with:
> * double: you can pass Double,Float,Long,Integer,Short,Character,Byte
> * float: you can pass Float,Integer
> * long: you can pass Long,Integer,Short,Character,Byte
> * ...
>
So conversions that are statically know to be non-lossy... But how to
capture these rules in generated code? Are the subclasses of Number
bounded?

It' seems
> Tom
>
>

--------------000000080702080309020700
Content-Type: text/html; charset=ISO-8859-15
Content-Transfer-Encoding: 8bit

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html;charset=ISO-8859-15"
http-equiv="Content-Type">
</head>
<body bgcolor="#ffffff" text="#000000">
Tom,<br>
<br>
Comments below.<br>
<br>
Tom Schindl wrote:
<blockquote cite="mid:iie1s1$9p2$1@news.eclipse.org" type="cite">
<pre wrap="">[...]
</pre>
<blockquote type="cite">
<pre wrap="">It's never been the intention for eSet to do any kind of type
conversion. In the case of int you'd do the same, and if you passed a
long that was too big, it would just truncate the value...
</pre>
</blockquote>
<pre wrap=""><!---->
Is it really a conversion when we talk about primitives? Isn't every int
a long - so to any method I can pass a long I'm free to pass an int,
short, char, byte?
</pre>
</blockquote>
Well of course the issue is, how does this generalize?<br>
<blockquote cite="mid:iie1s1$9p2$1@news.eclipse.org" type="cite">
<pre wrap="">
</pre>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">-----------8&lt;-----------

My understanding of autoboxing is that this is more or less what the
compiler makes from setMyLongFeature((Long)newValue) anyways because at
the bytecode level you'll get something like this:

-----------8&lt;-----------
setMyLongFeature(((Long)newValue).longValue());
-----------8&lt;-----------

This way a call to myinstance.eSet(MY_LONG_FEATURE,10) works like
myinstance.setMyLongFeature(10).

So my suggestion would be to make the eSet-code behave like statically
typed Java method calls in terms of primitive conversion (for types like
long/double this is as easy as shown above) for other types the
primitive conversion rules have be taken into account.

</pre>
</blockquote>
<pre wrap="">I don't think this is a great idea. It makes all numbers
interchangeable in any direction, some of them lossy. That's just not
the intent...
</pre>
</blockquote>
<pre wrap=""><!---->
This is certainly NOT true for double/long as you wrote "some of them
lossy".
</pre>
</blockquote>
Actually it's is true for Double-&gt;Long.<br>
<blockquote cite="mid:iie1s1$9p2$1@news.eclipse.org" type="cite">
<pre wrap="">
Would it change your opinion when I tell you that Java-Reflection does
what I request here?
</pre>
</blockquote>
Not necessarily.
Re: EObject#eSet and autoboxing [message #652426 is a reply to message #652418] Thu, 03 February 2011 20:22 Go to previous message
Thomas Schindl is currently offline Thomas SchindlFriend
Messages: 6505
Registered: July 2009
Senior Member
Am 03.02.11 20:48, schrieb Ed Merks:
> Tom,
>
> Comments below.
>
> Tom Schindl wrote:
>> [...]
>>
>>> It's never been the intention for eSet to do any kind of type
>>> conversion. In the case of int you'd do the same, and if you passed a
>>> long that was too big, it would just truncate the value...
>>>
>>
>> Is it really a conversion when we talk about primitives? Isn't every int
>> a long - so to any method I can pass a long I'm free to pass an int,
>> short, char, byte?
>>
> Well of course the issue is, how does this generalize?
>>
>>>> -----------8<-----------
>>>>
>>>> My understanding of autoboxing is that this is more or less what the
>>>> compiler makes from setMyLongFeature((Long)newValue) anyways because at
>>>> the bytecode level you'll get something like this:
>>>>
>>>> -----------8<-----------
>>>> setMyLongFeature(((Long)newValue).longValue());
>>>> -----------8<-----------
>>>>
>>>> This way a call to myinstance.eSet(MY_LONG_FEATURE,10) works like
>>>> myinstance.setMyLongFeature(10).
>>>>
>>>> So my suggestion would be to make the eSet-code behave like statically
>>>> typed Java method calls in terms of primitive conversion (for types like
>>>> long/double this is as easy as shown above) for other types the
>>>> primitive conversion rules have be taken into account.
>>>>
>>>>
>>> I don't think this is a great idea. It makes all numbers
>>> interchangeable in any direction, some of them lossy. That's just not
>>> the intent...
>>>
>>
>> This is certainly NOT true for double/long as you wrote "some of them
>> lossy".
>>
> Actually it's is true for Double->Long.

I meant there's not potential loss for methods who get passed in a
double or long ;-)

>> Would it change your opinion when I tell you that Java-Reflection does
>> what I request here?
>>
> Not necessarily. Complexity is something that is often best avoided.
> So something that's not been an issue for almost 10 years might be
> better off left as is.

[...]

> I guess the question is, what are the rules?
>> To a method with:
>> * double: you can pass Double,Float,Long,Integer,Short,Character,Byte
>> * float: you can pass Float,Integer
>> * long: you can pass Long,Integer,Short,Character,Byte
>> * ...
>>
> So conversions that are statically know to be non-lossy... But how to
> capture these rules in generated code? Are the subclasses of Number
> bounded?

I'll try to find that out ;-)

Tom
Previous Topic:none elements for CrossReferencer-Iterator
Next Topic:loading a genmodel
Goto Forum:
  


Current Time: Wed Oct 16 04:47:44 GMT 2019

Powered by FUDForum. Page generated in 0.01420 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top