ClassCastException of same object type

#1

I have ObjectDB partially working with my project. At the moment it seems to be saving objects and retrieving objects ok in the main project. However, when I make a plugin for the project, the new objects are persisted but not retrieved. I get the following error:

java.lang.ClassCastException: org.sportscoring.ssv.xc.core.XCCompetitorCount cannot be cast to org.sportscoring.ssv.xc.core.XCCompetitorCount

The object "org.sportscoring.ssv.xc.core.XCCompetitorCount" implements an interface called "ICoreObject". The source code is attached.

When I debug, the object is retreived but when I try to add it to do the following as below

this.XCCompetitorCounts.add((XCCompetitorCount) obj);

where is ArrayList <XCCompetitorCount> XCCompetitorCounts = new ArrayList<XCCompetitorCount>();

I then get the exception. 

The retrieved object seems to exist only as an ICoreObject, not as a XCCompetitorCount. Yet using the Explorer I can see it in the db as a XCCompetitorCount.

I would appreciate any clues as to what might be happening.

BTW. Thank you for your previous assistance.

#2

I thought I would add some further information. I am using ObjectDB 2.2.8 and Java 1.6. I am making an EclipseRCP project that records athletic/swimming, etc results. The core of the projects works as expected. The problem is in a plugin I am making for the project to do team scoring. (I expect I will have similar problems in other plugins I have in mind)

To hopefully make it clearer, the following method is where there exception occurs:

public  SSVXCObjectParcel load() throws GenderException, StorageFailedToConnectException, StorageMissingTypeException{
  cop = new SSVXCObjectParcel();
  cop.addListener(this);
  this.addListener(cop);
  List<XCCompetitorCount> list =  ((IStorageDb)parent_storage).getEntityManager().createQuery("select e from XCCompetitorCount e", XCCompetitorCount.class).getResultList();
  for(XCCompetitorCount ico : list){
   cop.add(ico);
  }
  this.loaded = true;
  return cop;
}

When the query is run, debugging shows that "list" contains the XCCompetitorCount objects I persisted earlier. The method fails in the line in bold, ie at the start of the for loop. If however, I change the method to look like:

List<XCCompetitorCount> list =  ((IStorageDb)parent_storage).getEntityManager().createQuery("select e from XCCompetitorCount e", XCCompetitorCount.class).getResultList();
  for(ICoreObject ico : list){
   cop.add(ico);
  }

then debugging moves past that line and fails in the cop.add() method at the line if(obj instanceof XCCompetitorCount){. ICoreObject is the interface that is implemented by all the persisted objects. Yet the TypedQuery should be returning XCCompetitorCount objects! The add() method is below with the alternate problem in bold

public void add(ICoreObject obj, boolean fireEvent) {
        if (obj == null) {
         ErrorHandler.error("Trying to add null object to Shield COP.  Ignoring...");
            return;
        }
         if (obj instanceof XCCompetitorCount) {
          if (!this.XCCompetitorCounts.contains(obj)) {
           this.XCCompetitorCounts.add((XCCompetitorCount) obj);
          }
         }
         else{
          ErrorHandler.error("Error trying to add object of unknown class "+obj.getClass().toString());
          }
        if (fireEvent) this.updateChanged(obj);

}

So it seems that the query is returning XCCompetitorCount objects that are not being recognised as XCCompetitorCount objects. I cannot figure out why.
       

#3

It seems as a class loader issue - ClassCastException on the same class is possible when the same class is loaded by two different class loaders, i.e. your application uses one class loader and ObjectDB uses another class loader to retrieve entity objects.

This may be caused by using ObjectDB as a separate Eclipse bundle.

Are you embedding ObjectDB as suggested in this thread?

You may also try setting the current thread context class loader before using ObjectDB:

Thread.currentThread().setContextClassLoader(MyEntity.class.getClassLoader());
ObjectDB Support
#4

Thanks for the reply. I am not using ObjectDb as a seperate eclipse bundle. It is embedded as per the thread you mentioned. I will have a look at the thread context loader.

Cheers

#5

I put in

Thread.currentThread().setContextClassLoader(XCCompetitorCount.class.getClassLoader());

I now get an exception on the line

em.persist(obj);

The field org.sportscoring.ssv.xc.core.XCCompetitorCount.externalSyncID is the @Id of the entity. Originally I had it as @PrePersist. I then tried explicitly setting it before persist(). However I keep geting the following stack trace.

[ObjectDB 2.2.8] javax.persistence.PersistenceException
Failed to get reference value of field field org.sportscoring.ssv.xc.core.XCCompetitorCount.externalSyncID using enhanced method (error 362)
at com.objectdb.jpa.EMImpl.persist(EMImpl.java:376)
at org.sportscoring.openscorercp.storage.Storage_ObjectDb.doEvent(Storage_ObjectDb.java:154)
at org.sportscoring.ssv.xc.storage.SSVXCStorage_ObjectDb.doEvent(SSVXCStorage_ObjectDb.java:195)
at org.sportscoring.openscorercp.util.TimedEventController.run(TimedEventController.java:104)
at java.lang.Thread.run(Thread.java:619)
Caused by: com.objectdb.o.UserException: Failed to get reference value of field field org.sportscoring.ssv.xc.core.XCCompetitorCount.externalSyncID using enhanced method
at com.objectdb.o.MSG.d(MSG.java:74)
at com.objectdb.o.UMR.M(UMR.java:858)
at com.objectdb.o.UMR.D(UMR.java:660)
at com.objectdb.o.UMR.q(UMR.java:357)
at com.objectdb.o.UML.s(UML.java:479)
at com.objectdb.o.MMM.X(MMM.java:797)
at com.objectdb.o.OBM.bv(OBM.java:384)
at com.objectdb.o.OBM.bv(OBM.java:249)
at com.objectdb.jpa.EMImpl.persist(EMImpl.java:373)
... 4 more
Caused by: java.lang.ClassCastException: org.sportscoring.ssv.xc.core.XCCompetitorCount cannot be cast to com.objectdb.spi.TrackableUserType
at com.objectdb.o.UMR.E(UMR.java:673)
at com.objectdb.o.UMR.D(UMR.java:657)
... 10 more
Exception in thread "Thread-5" [ObjectDB 2.2.8] Unexpected exception (Error 990)
  Generated by Java HotSpot(TM) Client VM 1.6.0_16 (on Windows XP 5.1).
Please report this error on http://www.objectdb.com/database/issue/new
com.objectdb.o.InternalException: java.lang.ClassCastException: org.sportscoring.ssv.xc.core.XCCompetitorCount cannot be cast to com.objectdb.spi.TrackableUserType
java.lang.ClassCastException: org.sportscoring.ssv.xc.core.XCCompetitorCount cannot be cast to com.objectdb.spi.TrackableUserType
at com.objectdb.o.MMM.af(MMM.java:1025)
at com.objectdb.o.UTY.aF(UTY.java:1185)
at com.objectdb.o.UTY.aE(UTY.java:1174)
at com.objectdb.o.ENH.a(ENH.java:46)
at com.objectdb.o.STA.T(STA.java:512)
at com.objectdb.o.STM.D(STM.java:408)
at com.objectdb.o.OBM.bH(OBM.java:884)
at com.objectdb.jdo.PMImpl.bH(PMImpl.java:2186)
at com.objectdb.o.OBM.bG(OBM.java:800)
at com.objectdb.o.OBM.flush(OBM.java:735)
at org.sportscoring.openscorercp.storage.Storage_ObjectDb.doEvent(Storage_ObjectDb.java:164)
at org.sportscoring.ssv.xc.storage.SSVXCStorage_ObjectDb.doEvent(SSVXCStorage_ObjectDb.java:195)
at org.sportscoring.openscorercp.util.TimedEventController.run(TimedEventController.java:104)
at java.lang.Thread.run(Thread.java:619)
#6

So this doesn't help, there is still duplicate class loading using different class loaders.

Could you post the project with instructions how to get the exceptions?

ObjectDB Support
#7

Hi

I just realised that the classloader for the XCCompetitorCount object should be fine. This application previously stored data in csv files. The application works fine with no classloader issues when using the csv reading storage classes.

I am now trying to abstract the data storage so that different types of storage are possible in order to allow previous data to still be read from csv files but allow users to store in an ObjectDB for newer data.

So is it a classloader issue for ObjectDb rather than the plugin classes?

#8

I have been reading some of the threads in the forum. Is my issue related to the fact that my plugin is trying to access ObjectDB through a superclass that in another plugin? Does each plugin need to have its own lib folder and a copy of ObjectDb in it and use that particular copy?

#9

That might be the reason. Try merging the two plugins to one plugin to see if it helps.

ObjectDB Support
#10

Tranferring the classes relating to objectdb from the supplementary plugin to the main plugin plus a few fixes allowed the application to work. Transferring the classes back caused the application to not work.

However, this solution is not appropriate for the application. I need to be able to change plugins depending on who uses the application. So the classes cannot be in the main plugin.

The next option seems to be to have another copy of objectdb in each plugin. However, the aim is to eventually have the application used over a network via the server. So having more than one copy of objectdb seems to be impractical.

Do you have any suggestions?

#11

This will have to be addressed in future ObjectDB versions.

ObjectDB Support
#12

After some experimentation and looking at Andreas Beckers' iAuthor project I found that I could convert the objectDB jar to an eclipse plugin. What I had not done was use BuddyLoading! This seems to have solved my problems as I can now access objects from other plugins without classcastexceptions.

Reply