Problems with Luna Nightly Runtime and ListBox [message #1124335] |
Thu, 03 October 2013 08:40  |
Eclipse User |
|
|
|
Yesterday I changed my target file from Kepler RC1 to Luna Nightly because I wanted to test a bug that was fixed in Luna (background.disabled property in SWT look and feel).
This made my application throw various exceptions in connection with AbstractListBox and AbstractTreeBox.
In my forms I have various Fields extending either AbstractListBox<Long> and AbstractTreeBox<Long>. On some of them I have defined the following method to sort the entries:
@Override
protected void execFilterLookupResult(LookupCall call, List<LookupRow> result) throws ProcessingException {
java.util.Collections.sort(result, new LookupRowComparator(LookupRowComparator.MODE_KEY));
}
And LookupRowComparator roughly looks as follows:
@Override
public int compare(LookupRow object1, LookupRow object2) {
if (object1 == null) return -1;
if (object2 == null) return 1;
if (mode == MODE_TEXT) {
return object1.getText().compareTo(object2.getText());
}
else { // mode == MODE_KEY
return ((Long) object1.getKey()).compareTo((Long) object2.getKey());
}
}
When opening this form, I now suddenly get the following exception:
!ENTRY org.eclipse.scout.rt.client 4 0 2013-10-03 14:35:16.387
!MESSAGE org.eclipse.scout.rt.client.services.common.exceptionhandler.internal.InternalClientExceptionHandlerService.differentiatedLog(InternalClientExceptionHandlerService.java:116) ProcessingException: ProcessingStatus[ERROR code=0 TabbedForm / Unexpected java.lang.ClassCastException: java.math.BigDecimal incompatible with java.lang.Long]
!STACK 0
ProcessingException[ProcessingStatus[ERROR code=0 TabbedForm / Unexpected java.lang.ClassCastException: java.math.BigDecimal incompatible with java.lang.Long]]
at org.eclipse.scout.rt.client.ui.form.FormUtility$InitFieldVisitor.visitField(FormUtility.java:170)
at org.eclipse.scout.rt.client.ui.form.fields.listbox.AbstractListBox.visitFields(AbstractListBox.java:888)
at org.eclipse.scout.rt.client.ui.form.fields.AbstractCompositeField.visitFields(AbstractCompositeField.java:268)
at org.eclipse.scout.rt.client.ui.form.fields.AbstractCompositeField.visitFields(AbstractCompositeField.java:268)
at org.eclipse.scout.rt.client.ui.form.fields.AbstractCompositeField.visitFields(AbstractCompositeField.java:268)
at org.eclipse.scout.rt.client.ui.form.fields.AbstractCompositeField.visitFields(AbstractCompositeField.java:268)
at org.eclipse.scout.rt.client.ui.form.AbstractForm.visitFields(AbstractForm.java:1002)
at org.eclipse.scout.rt.client.ui.form.FormUtility.initFormFields(FormUtility.java:77)
at org.eclipse.scout.rt.client.ui.form.AbstractForm.initForm(AbstractForm.java:1179)
at org.eclipse.scout.rt.client.ui.form.AbstractForm.startInternal(AbstractForm.java:685)
at org.eclipse.minicrm.client.ui.forms.TabbedForm.startDisplay(TabbedForm.java:303)
at org.eclipse.minicrm.client.ui.desktop.Desktop$TabbedFormTool.execAction(Desktop.java:1279)
at org.eclipse.scout.rt.client.ui.action.AbstractAction.doAction(AbstractAction.java:292)
at org.eclipse.scout.rt.client.ui.action.AbstractAction$P_UIFacade.fireActionFromUI(AbstractAction.java:629)
at org.eclipse.minicrm.ui.swt.application.CoolbarButton$1.run(CoolbarButton.java:175)
at org.eclipse.scout.rt.ui.swt.concurrency.SwtScoutSynchronizer$1.runVoid(SwtScoutSynchronizer.java:60)
at org.eclipse.scout.rt.client.ClientJob.runStatus(ClientJob.java:189)
at org.eclipse.scout.rt.client.ClientJob.runTransactionWrapper(ClientJob.java:172)
at org.eclipse.scout.rt.client.ClientJob.run(ClientJob.java:159)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
Caused by: java.lang.ClassCastException: java.math.BigDecimal incompatible with java.lang.Long
at org.eclipse.minicrm.client.utils.LookupRowComparator.compare(LookupRowComparator.java:106)
at org.eclipse.minicrm.client.utils.LookupRowComparator.compare(LookupRowComparator.java:1)
at java.util.Arrays.mergeSort(Arrays.java:2874)
at java.util.Arrays.mergeSort(Arrays.java:2886)
at java.util.Arrays.mergeSort(Arrays.java:2886)
at java.util.Arrays.sort(Arrays.java:3251)
at java.util.Arrays.sort(Arrays.java:3269)
at java.util.Collections.sort(Collections.java:1961)
at org.eclipse.minicrm.client.ui.forms.TabbedForm$MainBox$MainGroupBox$TabBox$Sandbox4Box$ListBoxField.execFilterLookupResult(TabbedForm.java:2624)
at org.eclipse.scout.rt.client.ui.form.fields.listbox.AbstractListBox.filterLookupResult(AbstractListBox.java:501)
at org.eclipse.scout.rt.client.ui.form.fields.listbox.AbstractListBox.execLoadTableData(AbstractListBox.java:183)
at org.eclipse.scout.rt.client.ui.form.fields.listbox.AbstractListBox.execPopulateTable(AbstractListBox.java:217)
at org.eclipse.scout.rt.client.ui.form.fields.listbox.AbstractListBox.loadListBoxData(AbstractListBox.java:474)
at org.eclipse.scout.rt.client.ui.form.fields.listbox.AbstractListBox.initFieldInternal(AbstractListBox.java:357)
at org.eclipse.scout.rt.client.ui.form.fields.AbstractFormField.initField(AbstractFormField.java:830)
at org.eclipse.scout.rt.client.ui.form.FormUtility$InitFieldVisitor.visitField(FormUtility.java:161)
... 19 more
The problem seems to be the following line in my comparator:
return ((Long) object1.getKey()).compareTo((Long) object2.getKey());
Changing my field definitions to AbstractListBox<BigDecimal> and my comparator to:
return ((BigDecimal) object1.getKey()).compareTo((BigDecimal) object2.getKey());
solves the problem, but is not really what I want to do...
Similarly, on those forms where I use AbstractListBox<Long> without the execFilterLookupResult() call, I get the following exeception the moment I tick a checkbox for one of the entries:
!ENTRY org.eclipse.scout.rt.client 4 0 2013-10-03 14:38:43.325
!MESSAGE org.eclipse.scout.rt.client.ui.basic.tree.AbstractTree.fireTreeEventInternal(AbstractTree.java:2180) fire TreeEvent["P_InternalTreeNode[Deutschland]" TYPE_NODES_UPDATED]
!STACK 0
java.lang.ArrayStoreException
at org.eclipse.scout.rt.client.ui.form.fields.treebox.AbstractTreeBox.syncTreeToValue(AbstractTreeBox.java:953)
at org.eclipse.scout.rt.client.ui.form.fields.treebox.AbstractTreeBox.access$2(AbstractTreeBox.java:935)
at org.eclipse.scout.rt.client.ui.form.fields.treebox.AbstractTreeBox$1.treeChanged(AbstractTreeBox.java:312)
at org.eclipse.scout.rt.client.ui.basic.tree.AbstractTree.fireTreeEventInternal(AbstractTree.java:2177)
at org.eclipse.scout.rt.client.ui.basic.tree.AbstractTree.fireNodesUpdated(AbstractTree.java:1957)
at org.eclipse.scout.rt.client.ui.basic.tree.AbstractTree.setNodeChecked(AbstractTree.java:1097)
at org.eclipse.scout.rt.client.ui.basic.tree.AbstractTreeNode.setChecked(AbstractTreeNode.java:401)
at org.eclipse.scout.rt.client.ui.basic.tree.AbstractTree.interceptNodeClickSingleObserver(AbstractTree.java:2071)
at org.eclipse.scout.rt.client.ui.basic.tree.AbstractTree.fireNodeClick(AbstractTree.java:2057)
at org.eclipse.scout.rt.client.ui.basic.tree.AbstractTree.access$2(AbstractTree.java:2054)
at org.eclipse.scout.rt.client.ui.basic.tree.AbstractTree$P_UIFacade.fireNodeClickFromUI(AbstractTree.java:2623)
at org.eclipse.scout.rt.ui.swt.basic.tree.SwtScoutTree$5.run(SwtScoutTree.java:475)
at org.eclipse.scout.rt.ui.swt.concurrency.SwtScoutSynchronizer$1.runVoid(SwtScoutSynchronizer.java:60)
at org.eclipse.scout.rt.client.ClientJob.runStatus(ClientJob.java:189)
at org.eclipse.scout.rt.client.ClientJob.runTransactionWrapper(ClientJob.java:172)
at org.eclipse.scout.rt.client.ClientJob.run(ClientJob.java:159)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
Again, changing the field to AbstractListBox<BigDecimal> solves the problem, but again, I don't really feel like changing the types of all my ListBox fields.
Just a wild guess: Could this have anything to do with the changes described in this thread: http://www.eclipse.org/forums/index.php/t/523968/ ?
|
|
|
|
|
|
Re: Problems with Luna Nightly Runtime and ListBox [message #1131048 is a reply to message #1130312] |
Thu, 10 October 2013 02:16   |
Eclipse User |
|
|
|
Ken Lee wrote on Wed, 09 October 2013 14:26I'm not quite sure what you are exactly targeting with the above quotation. Do you mean that the migration process to use the legacy SQL style is too complex?
No, the migration process was easy enough to follow.
Ken Lee wrote on Wed, 09 October 2013 14:26I guess that you are using a DB that doesn't support explicit integer types directly. Instead it uses something like NUMERIC(10,0) to define an integer type-like column (e.g. for a primary key).
In my playground application I'm using a derby DB (it's based on the minicrm tutorial). I use that application to "try out" new features, so I don't have to do that in our production code (which uses Hibernate instead of Scout's SQL services, so it's not an issue there).
My concern was that with the new mapping method, it was impossible to use AbstractListBox<Long>. I didn't realise that this limitation only applies for databases with the limitation I quote above, so I thought it was a general problem
that you could either have "good mapping" or the ability to use AbstractListBox<Long> but not both.
If this is indeed only happening because I'm using derby, and will work with "proper" databases that have explicit numerical types (though I'm not familiar enough with other database engines to know which ones do; I believe DB2 on Mainframe also only has "DECIMAL(x,x)") then I guess my point is less relevant.
Ken Lee wrote on Wed, 09 October 2013 14:26We had several Scout projects that encountered the problem of having mixed up data types in a single column independently and simultaneously. So we decided to standardize to conversion to a certain Java data type which corresponds to the Java data type read from the JDBC driver.
Oh, I understand the reason behind the change (I loosely followed that thread), I just didn't realise it would affect anything else than tables and was surprised that it broke existing code in cases where no mixed datatypes were used.
|
|
|
Re: Problems with Luna Nightly Runtime and ListBox [message #1131077 is a reply to message #1131048] |
Thu, 10 October 2013 02:58   |
Eclipse User |
|
|
|
Urs Beeli wrote on Thu, 10 October 2013 02:16No, the migration process was easy enough to follow.
Ok, good to know because we also think that the migration should be easy enough.
Urs BeeliIn my playground application I'm using a derby DB (it's based on the minicrm tutorial).
As far as I remember, Derby DB returns numeric or decimal JDBC data types. Therefore (in the "old days"), you would get a Long or a Double data type in Java as shown in the other forum thread.
Urs BeeliI didn't realise that this limitation only applies for databases with the limitation I quote above, so I thought it was a general problem
that you could either have "good mapping" or the ability to use AbstractListBox<Long> but not both.
Yes, the change is only limited to DB queries where numerical or decimal values are involved. If it was a general problem, we would definitely have to create a follow bug 
Urs BeeliIf this is indeed only happening because I'm using derby, and will work with "proper" databases that have explicit numerical types (though I'm not familiar enough with other database engines to know which ones do; I believe DB2 on Mainframe also only has "DECIMAL(x,x)") then I guess my point is less relevant.
The "standard" operations like filling up the formdata with the result of the DB or loading data into a Scout table are not affected by the change because they use the TypeCastUtility in the background to convert the BigDecimal into a Long or Double value.
The problem arises however, if you load the table result into a Java Object array and do some manual sorting. With the old conversion, you might expect something of type Long or Double but you will get a BigDecimal data type now. This is exactly what happened in your example above.
Urs Beeli
Oh, I understand the reason behind the change (I loosely followed that thread), I just didn't realise it would affect anything else than tables and was surprised that it broke existing code in cases where no mixed datatypes were used.
In contrast to your example, in the other Scout projects they were expecting pure Double data types but finally received a mix of Long and Double values. That's the reason for the "standardization" of the conversion.
I'm glad that we could tackle this problematic already at an early stage. I'm sure that the same question will arise again if more projects use Scout 3.10.
|
|
|
Re: Problems with Luna Nightly Runtime and ListBox [message #1131216 is a reply to message #1131077] |
Thu, 10 October 2013 05:59  |
Eclipse User |
|
|
|
Ken Lee wrote on Thu, 10 October 2013 08:58The problem arises however, if you load the table result into a Java Object array and do some manual sorting. With the old conversion, you might expect something of type Long or Double but you will get a BigDecimal data type now. This is exactly what happened in your example above.
Form what I understood; we can summarize it like this:
Previously the SQL Layer was taking care of the conversion NUMERIC (SQL) --> Long (Java). Today the conversion is: NUMERIC --> BigDecimal.
From what I understood from the other forum thread, this is necessary.
* * *
I think that AbstractSqlLookupService is a legitimate use case where you might want to control the type of the key:
You know where the LookupService is used (by wich LookupCall). With the old implementation, you used this LookupCall in a SmartField<Long> or TreeBox<Long> field.
This is a very representative use case. From what I understood from Urs Beeli: in a lot of cases you know that you have a number without decimal part in your NUMERIC column and for those cases the old Long type was easier to work with than the new BigDecimal type.
Now my proposal:
When we write the query of in the SqlLookupService, we know the type of the Key we want to have. What about adding a getConfiguredKeyClass() in the AbstractSqlLookupService? In the execLoadLookupRows(..) we add an additional step in the default implementation: If keyClass == null (default returned value) the step does nothing. If not null (Long.class for example), for each rows of the result set we do the casting of the key with the TypeCastUtility (the key of the LookupRow is Column 0 in the Object[][] data array). This is near from what the previous SQL was doing.
|
|
|
Powered by
FUDForum. Page generated in 0.25894 seconds