# [GWT] Probleme beim asynchronen Methodenaufruf mit GWT-RPC



## kidsos (10. Apr 2010)

Hallo,

ich arbeite zur Zeit an einer privaten Webanwendung mit dem GWT und bekomme das GWT-RPC nicht so richtig zum Laufen.

Nun, worum gehts genau. Auf der Server-Seite der Anwendung habe ich eine Objektmodell mit JAXB erstellt. Per RPC soll der Client nun eine Methode asynchron aufrufen, damit der Client das zurückgegebene Objekt weiter verarbeiten kann.

Leider wirft mir der GWT-Compiler beim Aufruf immer wieder einen Fehler (siehe Anhang). Da steht zwar, dass ich vielleicht ein "required module" vergessen hätte, aber was muss ich da genau wie machen. Laut dem GWT-Tutorial auf der Google-Seite muss ich der Module-Datei nichts hinzufügen oder verändern.

Wäre super, wenn mir da jemand dabei helfen könnte, das Problem zu lösen!

Die 3 entscheidenden Klassen bzw. Interfaces sehen folgendermaßen aus:

```
package de.application.server;

import java.io.FileNotFoundException;
import java.io.FileReader;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import de.application.client.ApplicationListService;

public class ApplicationListServiceImpl extends RemoteServiceServlet implements
		ApplicationListService {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public ApplicationList getList() {
		JAXBContext context;
		ApplicationList list = null;
		try {
			context = JAXBContext.newInstance(ApplicationList.class);
			Unmarshaller um = context.createUnmarshaller();
			list = (ApplicationList) um.unmarshal(new FileReader(
					"club-jaxb.xml"));
		} catch (JAXBException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return list;
	}
}
```


```
package de.application.client;

import com.google.gwt.user.client.rpc.AsyncCallback;

import de.application.server.ApplicationList;

public interface ApplicationListServiceAsync {

	void getList(AsyncCallback<ApplicationList> callback);

}
```
Nach dem Fehler scheint mir das so, dass der die ApplicationList-Klasse vom Server nicht finden kann und daher den Fehler wirft. Muss ich da irgendwo noch eine Referenz hinzufügen?


```
package de.application.client;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

import de.application.server.ApplicationList;

@RemoteServiceRelativePath("appList")
public interface ApplicationListService extends RemoteService {

	ApplicationList getList();
}
```


----------



## gee_20_4_7 (10. Apr 2010)

Hi, also du solltest hier mal noch 2 weitere Dateien anbieten: 

1. *die web.xml*, in der du die Services bekannt machst (hier vermute ich, dass da ein Problem vorliegt)
2. *die app.gwt.xml*, in der du z.B. den Einstiegspunkt bekannt machst. Laut der Fehlermeldung im Anhang scheint mir da auch etwas im Argen.
will mich da aber nicht 100%ig festlegen, deshalb stelle doch mal bitte die beiden Dateien zur Verfügung.


----------



## kidsos (11. Apr 2010)

Hier noch die 2 entsprechenden Dateien:

Application.gwt.xml
[XML]
<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='application'>
  <inherits name='com.google.gwt.user.User'/>

	<inherits name="com.google.gwt.http.HTTP" />
	<inherits name="com.google.gwt.i18n.I18N" />
	<inherits name='com.google.gwt.user.theme.standard.Standard' />
  <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
  <!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/>     -->

  <entry-point class='de.application.client.Application'/>

  <source path='client'/>
  <source path='shared'/>
</module>
[/XML]

web.xml
[XML]
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
	<!-- Default page to serve -->
	<welcome-file-list>
		<welcome-file>Application.html</welcome-file>
	</welcome-file-list>

	<!-- Servlets -->
	<servlet>
		<servlet-name>appListServiceImpl</servlet-name>
		<servlet-class>de.application.server.ApplicationListServiceImpl</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>appListServiceImpl</servlet-name>
		<url-pattern>/application/ApplicationListService</url-pattern>
	</servlet-mapping>
</web-app>
[/XML]


----------



## gee_20_4_7 (11. Apr 2010)

Jetzt stellt sich mir die Frage was ApplikationList ist - eine Liste, die auf beiden Seiten verwendet wird? Was wird in dieser Liste gehalten - vllt ein Typ der auf beiden Seiten benutzt wird? Wenn das der Fall ist, dann leg mal die Klassen in das shared-Paket. 

Es ist auf jeden Fall schwer wenn man keinen kompletten Einblick hat. In den beiden XML-Dateien kann ich nichts besonderes erkennen. 

Was mich wundert ist, dass du in der ServiceImpl die ApplicationList verwendest - aber nirgendwo ein entsprechender import steht, nee stimmt kommt aus dem Interface...vll wirklich mal die List in das shared paket verschieben. Denn wenn du zur Laufzeit etwas vom Server importierst - ist es de facto nicht verfügbar...
Versuche vllt mal noch den RelativePath deines ApplicationService Interfaces zu überprüfen - also den Wert der Annotation.

Ja leider kann ich hier nur vermuten, aber es hat sich auch in meinen ersten Versuchen gezeigt, dass Klassen, die auf client-, wie auch auf der serverseite verfügbar sein müssen eben in das sharedpaket gehören, was hier evtl der entscheidende Tipp ist.

Sorry für den unkoordinierten Schreibstil, aber ich hatte jetzt nicht so viel Zeit das alles komplett zu überdenken.


----------



## kidsos (11. Apr 2010)

Also die ApplicationList-Klasse enthält eine Liste von ApplicationItem-Objekten, die ApplicationItem-Klasse wiederum enthält String-Objekte, usw. Hier mal die ApplicationList-Klasse:

```
@XmlRootElement(name = "jobApplications")
@XmlAccessorType(XmlAccessType.NONE)
public class ApplicationList {

	private ArrayList<ApplicationItem> itemList;

	public ApplicationList() {
		setList(new ArrayList<ApplicationItem>());
	}

	public void setList(ArrayList<ApplicationItem> itemList) {
		this.itemList = itemList;
	}
	
	@XmlElement(name = "company")
	public ArrayList<ApplicationItem> getList() {
		return itemList;
	}
}
```



> Ja leider kann ich hier nur vermuten, aber es hat sich auch in meinen ersten Versuchen gezeigt, dass Klassen, die auf client-, wie auch auf der serverseite verfügbar sein müssen eben in das sharedpaket gehören, was hier evtl der entscheidende Tipp ist.


Wo ich mir das grad so durch den Kopf gehen lasse, haste eigentlich Recht. Wenn das irgendwann mal alles klappt, sollen ja vom Server ein ApplicationList-Objekt an den Client geschickt werden. Anders rum soll es natürlich auch funktionieren, denn dann kann ich ja ein ApplicationList-Objekt an den Server schicken, der mir dann die passende XML-Datei erstellt. Ist ja Sinn der ganzen Sache. Also die notwendigen Klassen dort rein.

Das Problem ist jetzt allerdings, dass ich mit JAXB eine bestimmte Klassen- und XML-Struktur aufgebaut habe, die in dem shared-Package nicht mehr funktioniert, da die XML-Annotationen nicht aufgelöst werden können. Außerdem hab ich da z.B. ein XMLGregorianCalender-Objekt. Die Klasse gibts ja im GWT nicht.

Wie kann man denn das jetzt lösen?

Ich hab hier ne Anleitung (Teil 1 + Teil 2) gefunden, die vom Prinzip her das macht, was meine Webanwendung später können soll. Allerdings wurde hier mit REST gearbeitet und die XML-Struktur wurde sehr einfach gehalten.


----------



## kidsos (12. Apr 2010)

> Das Problem ist jetzt allerdings, dass ich mit JAXB eine bestimmte Klassen- und XML-Struktur aufgebaut habe, die in dem shared-Package nicht mehr funktioniert, da die XML-Annotationen nicht aufgelöst werden können. Außerdem hab ich da z.B. ein XMLGregorianCalender-Objekt. Die Klasse gibts ja im GWT nicht.


Das ich nicht gleich drauf gekommen bin. Lösung des ganzen ist es, die jaxb-impl.jar (aus dem dem lib-Ordner) als Classpath dem Projekt hinzuzufügen. Dadurch können die XML-Annotationen der jeweiligen Klassen im shared-Package aufgelöst werden. Zusätzlich dann noch in den Klassen Serializable implementieren, damit die Objekte auch serialisiert werden können. 
Komisch finde ich, dass der Compiler immer noch eine server.gwt.xml verlangt. Hab ich probehalber dort einfach ohne irgendwelchen Schnickschnack erstellt. Scheinbar muss man da nichts besonderes angeben. Die Existenz dieser Datei genügt.

Auf jeden Fall klappt es so! :toll:

Der Compiler wirft nur noch folgende Warnung aus, ansonsten funktioniert es aber:

```
[WARN] Server class 'com.sun.xml.bind.v2.ContextFactory' could not be found in the web app, but was found on the system classpath
   [WARN] Adding classpath entry 'file:/C:/jaxb-ri-20091104/lib/jaxb-impl.jar' to the web app classpath for this session
   For additional info see: file:/C:/Users/Chabo/eclipse/plugins/com.google.gwt.eclipse.sdkbundle.2.0.3_2.0.3.v201002191036/gwt-2.0.3/doc/helpInfo/webAppClassPath.html
```
Wie müsste ich das denn in der web.xml angeben?


----------



## gee_20_4_7 (12. Apr 2010)

Das sieht mir so aus, dass die jaxb-impl.jar nicht im lib-Verzeichnis gefunden werden kann...versuchs mal mit einem copy & paste in dieses verzeichnis... war/webinf/lib/
mehr kann ich dir an dieser Stelle auch nicht raten...


----------



## kidsos (12. Apr 2010)

Das wars. Jetzt läuft alles rund. 

Bekommst von mir ein großes Danke! :toll:


----------



## gee_20_4_7 (12. Apr 2010)

na da bin ich ja froh...kannst ja den thread mal als erledigt markieren...
und viel spaß noch beim gwtn


----------

