ClassCastException beim transfer von Objekten über RMI

  • Themenstarter Themenstarter MaRsuPiLaMi3
  • Beginndatum Beginndatum
M

MaRsuPiLaMi3

Hallo zusammen,

ich steh vor folgenden Problem:

Ich habe einen Client/Server-Struktur mit RMI realisiert. In dieser gibt es ein SingleSignOn. Dieser generiert ein TicketImpl object, das das interface Ticket und Serializable implementiert. Wenn ich nun dieses Object per RMI übertrage, dann bekomme ich auf Clientseite eine Classcastexception, dass TicketImpl nicht nach Ticket gecastet werden kann.

Für mich ergibt diese Fehlermeldung kein Sinn und ich komme einfach nicht weiter.

Achja, der ganze Schmuddel läuft unter Java 1.6 und innerhalb eines OSGi-Frameworks als Bundle (mehrere), wobei die hier zu sehende Interfaces in einem anderen Bundle liegen als die Implementationen.
Die Proxy-Objekte werden in das Implementierungsbundle kopiert und dort über einen Classerver bereitgestellt (deployordner innerhlab des bundles)

Ticket.java (Interface)
Code:
public interface Ticket {
	/**
	 * Returns the <code>ident</code> by which the user will be identified
	 * @return The identification string
	 */
	public String getIdent();
}
TicketImpl.java
Code:
public class TicketImpl implements Ticket, Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 4408701785720874837L;
	private String ident = "";
	
	public TicketImpl(String ident){
		this.ident = ident;		
	}
	public String getIdent(){
		return this.ident;
	}
	
	public boolean equals(Object o){
		if(o instanceof Ticket){
			if(ident.equals(((Ticket)o).getIdent())){
				return true;
			}
		}
		return false;
	}
	
	public int hashCode(){
		return this.ident.hashCode();
	}
}
SSOSErviceRMI.java (Interface)
Code:
public interface SSOServiceRMI extends Remote {
	static final String REGISTRY_NAME = "SSOServiceRMI";
	/**
	 * Authenticates a user by its given <code>username</code> and <code>password</code>
	 * If an error occurs or a crediential check fails, an exception will be thrown
	 * @param username The users username (not to be confused with the ident)
	 * @param password The users password
	 * @throws IllegalParemeterException will be thrown if the supplied <code>username</code> is null or an empty string
	 * @throws BadCredentialsException will be thrown if the supplied <code>username</code> and <code>password</code> don't match
	 * @throws RemoteException will be thrown if an error in the remote management interface occurs      
	 */
	public Ticket signOn(String username, String password) 
			throws RemoteException, IllegalParameterException, BadCredentialsException;
}
}
SSOServiceRMIImpl.java
Code:
public class SSOServiceRMIImpl implements SSOServiceRMI{
	transient private SSOServiceImpl sso = null;   //instance of the SSOService implementation
	
	public SSOServiceRMIImpl(SSOServiceImpl sso) {
		this.sso = sso;
	}

	public Ticket signOn(String username, String password)throws RemoteException, IllegalParameterException,
			BadCredentialsException {
		return new TicketImpl("Blaa");//sso.signOn(username, password);   //authenticates a user by the given username and password
												 //if the authentication is fine, the ticket will be returned
	}
}

Aufrufende Code (Ausschnitt aus Activator.java)
Code:
	String host = "localhost";
	 int port = 1099;
			Registry registry = LocateRegistry.getRegistry(host, port);
			SSOServiceRMI service = (SSOServiceRMI) registry
					.lookup(SSOServiceRMI.REGISTRY_NAME);
			
			if(service != null){
				try{
					BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
					System.out.print("Username: ");
					String user = stdin.readLine();
					System.out.print("Passwort (Achtung wird angezeigt!): ");
					String pass = stdin.readLine();

					Object ticket = service.signOn(user, pass);
catch(Exception e) {e.printStrackTrace();}} // Zeile 76 (Siehe Exception)


Die Exception
Code:
java.lang.ClassCastException: se.kommedia.sso.ticket.TicketImpl cannot be cast to se.kommedia.sso.lib.ticket.Ticket
	at $Proxy2.signOn(Unknown Source)
	at getssoserver.Activator.start(Activator.java:76)
	at org.eclipse.osgi.framework.internal.core.BundleContextImpl$2.run(BundleContextImpl.java:999)
	at java.security.AccessController.doPrivileged(Native Method)
	at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:993)
	at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:974)
	at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:346)
	at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:260)
	at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:252)
	at org.eclipse.osgi.framework.internal.core.FrameworkCommandProvider._start(FrameworkCommandProvider.java:260)
	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 org.eclipse.osgi.framework.internal.core.FrameworkCommandInterpreter.execute(FrameworkCommandInterpreter.java:150)
	at org.eclipse.osgi.framework.internal.core.FrameworkConsole.docommand(FrameworkConsole.java:291)
	at org.eclipse.osgi.framework.internal.core.FrameworkConsole.console(FrameworkConsole.java:276)
	at org.eclipse.osgi.framework.internal.core.FrameworkConsole.run(FrameworkConsole.java:218)
	at java.lang.Thread.run(Unknown Source)

Grüsse und danke
Stefan
 
Zuletzt bearbeitet von einem Moderator:
Hallo,

kann sein, dass du beim TicketImpl generierungs Methode als Rückgabetyp anstatt Ticket den TicketImpl hast?

Gruß
lernen.2007
 
Hallo,

kann sein, dass du beim TicketImpl generierungs Methode als Rückgabetyp anstatt Ticket den TicketImpl hast?

Gruß
lernen.2007
Siehe Code, aber nein, es wird immer Ticket zurück gegeben.

Haben die Klassen auf beiden Seiten die Gleiche serialVersionUID?

Gruß
Ollie
Kann ich nicht nachgucken die Exception kommt genau an der Stelle wo das Ticket über den Proxy geht. Sprich es kommt garnicht erst dazu, das das Ticket auf Clientseite in eine Variable gespeichert wird.

Am Rande:
Wenn ich das ganze ohne RMI mache, dann funktioniert es einwandfrei!

Gruß
Stefan
 
Wie "kann ich nicht nachgucken"? Das steht als Property in deinen .java Files drin. Wenn du die nicht definiert hast, brauchst dich nicht wundern, wenn die Exception fliegt ;)

REINHAUN!
 
Wie du oben dem Code entnehmen kannst ist dem Ticket eine SerialVersionUID zugewiesen.
Auf clientseite kommt genau diese Klasse an, da diese über ein ClassFileServer vom Server geladen wird. Sprich der Client holt sich erst die Klasse, und das sind genau die gleichen ;)
 
Ähm von was den Stacky? Oben siehst du den Stacky doch !?
 
Zuletzt bearbeitet von einem Moderator:
Args... da postet jemand endlich mal ne Vernünftige Anfrage und ich bin zum Lesen zu blöd ^^.

Kann es sein, dass das OSGi den Proxy mehrfach generiert? Also von unterschiedlichen Classloadern? Das würde erklären, warum trotz gleicher serialVersionUID im Target das casten nicht tut.

Gruß
Ollie
 
Danke für den Tipp, letztendlich war es genau so. 2 verschiedene ClassLoader haben die TicketImpl.class geladen wodurch die natürlich unkompatible waren.
Durch ein verschieben der TicketImplementierung in das Interface-Bundle hat sich das Problem gelöst.

Danke und -> Done!
 
Zurück