# ClassCastException



## BDiegelmann (16. Januar 2007)

Hallo zusammen,

ich möchte eine Referenz eines Objektes über ein OSGI Service holen. Jedoch bekomme ich beim Zuweisen immer eine ClassCastException. Ich blicks nicht woran es liegt.

```
try
          {
            
            Object o = context.getService(serviceRef);
            if (o instanceof IsoTP)
              System.out.println("instance of!!");
            System.out.println(o.getClass());
            tp = (IsoTP) context.getService(serviceRef);
            
          }
```

Registriert hab ich den Service folgendermaßen:


```
tpServiceReg = context.registerService(IsoTP.class.getName(), tp, null);
```

Und das was rauskommt ist das:


```
Server is started.
fw>$INFO 240 Service export: edag.can.controller.CANController
INFO 240 CANController-Bundle gestartet
INFO 241 ISO-TP Bundle gestartet
INFO 241 CANController Service referenziert.
DEBUG 240 ServiceEvent.REGISTERED
in if tpRef == null
edag.can.transport.IsoTP@4845aa
class edag.can.transport.IsoTP
java.lang.ClassCastException: edag.can.transport.IsoTP
        at edag.can.controller.peak.Activator.serviceChanged(Activator.java:99)
        at com.prosyst.mbs.impl.framework.EventsManager.serviceChanged(EventsMan
ager.java:681)
        at com.prosyst.mbs.impl.framework.BundleContextImpl.registerService(Bund
leContextImpl.java:299)
        at com.prosyst.mbs.impl.framework.BundleContextImpl.registerService(Bund
leContextImpl.java:267)
        at com.prosyst.mbs.impl.framework.BundleContextImpl.registerService(Bund
leContextImpl.java:321)
        at edag.can.transport.Activator.start(Activator.java:46)
        at com.prosyst.mbs.impl.framework.BundleImpl.startIt(BundleImpl.java:306
3)
        at com.prosyst.mbs.impl.framework.BundleImpl.simpleStart(BundleImpl.java
:991)
        at com.prosyst.mbs.impl.framework.BundleImpl.start0(BundleImpl.java:904)

        at com.prosyst.mbs.impl.framework.BundleImpl.start(BundleImpl.java:814)
        at com.prosyst.mbs.impl.framework.BundleImpl.start(BundleImpl.java:592)
        at com.prosyst.mbs.impl.services.pmp.Administration.startBundle(Administ
ration.java:193)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at com.prosyst.mbs.impl.services.pmp.InvocationThread.run(InvocationThre
ad.java:89)
        at com.prosyst.util.impl.tpt.threadpool.Executor.run(Executor.java:136)
```

Obwohl die ganzen Debug-Ausgaben die ich da rein gebaut habe richtig zu sein scheinen,  es nicht.
Kann mir da jemand auf die Sprünge helfen?


----------



## zeja (16. Januar 2007)

Deine if-Abfrage umfasst nur noch eine Zeile. Liegts vllt daran oder war das nur das kürzen fürs Forum?


----------



## Thomas Darimont (16. Januar 2007)

Hallo,

kann es sein, dass du hier unterschiedliche ClassLoader verwendest? In der JVM ist nur das Tupel aus (Class,ClassLoader) einedeutig. Sprich es kann passieren dass eine Klasse mit dem gleichen namen von zwei unterschiedlichen ClassLoadern geladen wurde...  diese Klassen kann man nicht aufeinander Casten... Vergleich doch mal an was getClass().getClassLoader() an der Klasse sagt die du vom Service zurück bekommst und die die du "lokal" an der Hand hast.

Gruß Tom


----------



## BDiegelmann (17. Januar 2007)

Danke, für die schnelle Antwort, ich hab das mit dem Classloader überprüft, und so wie ich die Sache sehe scheinen die überein zu stimmen.
Ich kann natürlich den Classloader der tp Objektes nicht ausgeben, da ja keine Instanz zugewiesen wurde. Dies wird ja erst mit getService() erledigt.
Ich hab aber den Classloader ausgegeben, nachdem ich es zum ersten mal erstellt habe und dann nochmal, nachdem vom Objekt o nach getService(). Bin mir nicht sicher ob das so richtig ist.
*Was aber nicht übereinstimmt sind die Classloader des Activators des Bundels das den Service referenzieren soll und der Classloader der zu referenzierenden Klasse.*
Ist das vieleicht das Problem?


Was mich aber verwundert ist der Ablauf. Es wird ein Event gesendet obwohl der Service erst nach diesem Event registriert wird. Kann man in der Ausgabe unten sehen. Die Klasse Transport registriert den Service erst nachdem der Fehler auftritt. Gibts da vieleicht einen Zusammenhang?


```
INFO 258 Service export: edag.can.controller.CANController
INFO 258 CANController-Bundle gestartet
INFO 259 ISO-TP Bundle gestartet
INFO 259 CANController Service referenziert.
DEBUG 258 ServiceEvent.REGISTERED
edag.can.transport.IsoTP@502819
Classloader vom CanActivator: com.prosyst.mbs.impl.framework.DefaultClassProvide
r@29c58e
class edag.can.transport.IsoTP
Classloader in CANController: com.prosyst.mbs.impl.framework.DefaultClassProvide
r@a4488
java.lang.ClassCastException: edag.can.transport.IsoTP
        at edag.can.controller.peak.Activator.serviceChanged(Activator.java:110)

        at com.prosyst.mbs.impl.framework.EventsManager.serviceChanged(EventsMan
ager.java:681)
        at com.prosyst.mbs.impl.framework.BundleContextImpl.registerService(Bund
leContextImpl.java:299)
        at com.prosyst.mbs.impl.framework.BundleContextImpl.registerService(Bund
leContextImpl.java:267)
        at com.prosyst.mbs.impl.framework.BundleContextImpl.registerService(Bund
leContextImpl.java:321)
        at edag.can.transport.Activator.start(Activator.java:47)
        at com.prosyst.mbs.impl.framework.BundleImpl.startIt(BundleImpl.java:306
3)
        at com.prosyst.mbs.impl.framework.BundleImpl.simpleStart(BundleImpl.java
:991)
        at com.prosyst.mbs.impl.framework.BundleImpl.start0(BundleImpl.java:904)

        at com.prosyst.mbs.impl.framework.BundleImpl.start(BundleImpl.java:814)
        at com.prosyst.mbs.impl.framework.StartupWatchdog.run(StartupWatchdog.ja
va:139)
In Start of Transport: class edag.can.transport.IsoTP

In Start of Transport:  Classloader in ISO-TP: com.prosyst.mbs.impl.framework.De
faultClassProvider@a4488
Classloader von Activator Transport: com.prosyst.mbs.impl.framework.DefaultClass
Provider@a4488
DEBUG 258 ServiceEvent.REGISTERED
Server is started.
fw>$DEBUG 258 ServiceEvent.REGISTERED
DEBUG 258 ServiceEvent.REGISTERED
```


----------



## BDiegelmann (17. Januar 2007)

Kann das Problem noch ein bisschen eingrenzen.

Der Fehler tritt immer dann auf wenn zwei Bundles sich gegenseitig referenzieren. Also wenn Bundle A einen Service von B nutzen will und B einen Service von A.
Wenn ich jetzt zum Beispiel ein Bundle C habe was die Services von A und B referenziert gibt es keine Probleme. Nur wenn A und B gegenseitig Services referenzieren.

Hat da OSGi ein Mechanismus vorgesehen wie man das machen kann? Ich komm da einfach nicht weiter. 


```
class A {
B b;
b.useService();

}

class B {
A a;
a.useService();
}
```

Wie mach ich das ohne die ClassloaderException ?

P.S.: Hab in der Spec. nochmal gestöbert. Da stehts auch drin. Frag mich nur wie das funktionieren soll. Ich hab doch gar kein Einfluss auf den Classloader?


> Bundles and classloaders
> Each bundle installed in the Framework that is resolved must have a classloader
> associated with it (Frameworks may have multiple classloaders per
> bundle). This classloader provides each bundle with its own namespace, to
> ...


----------



## Thomas Darimont (17. Januar 2007)

Hallo,

schau doch mal ob du dieses Problem nicht über Buddy-Classloading lösen kannst...
http://eclipsezone.com/articles/eclipse-vms/?source=archives

Gruß Tom


----------

