XmlJavaTypeAdapter füllt die Liste nicht

Hallo liebe Community,
der Mist bringt mich langsam echt auf die Palme.

Ich hab eine XML Datei, die schaut im groben so aus:
[XML]




0.309469 -0.921392 0.450065


-0.246077 0.582705 0.060732







[/XML]

So. Diese Datei möchte ich auslesen, daher habe ich mir eine Struktur überlegt.
Ich hab JVXBean.java (die enthält einen XmlElementWrapper(name=“geometries”), GeometryBean.java, PointSetBean.java.
Eigentlich wollte ich auch in die PointSetBean ein XmlElementWrapper für “points” hinzufügen, allerdings hat das nie ganz geklappt, weil es nicht funktionierte, einen XmlElementWrapper UND ein XmlJavaTypeAdapter gleichzeitig zu benutzen… (es kamm dann immer die Fehlermeldung, es muss sich bei dem Typen um eine Collection oder ein Array handeln… meines war übrigens eine ArrayList<double[]>. Nach einigem suchen via google fand ich einen BugReport für JAXB zu diesem problem…)

Also dachte ich mir, was sollst, schreibste dir halt noch eine Klasse, PointsBean.java. Die schaut jetzt so aus:


import java.util.LinkedList;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement( name = "points" )
public class PointsBean {
	private int numOfPoints;
	
	@XmlElement( name = "p" )
	@XmlJavaTypeAdapter( PointAdapter.class )
	public LinkedList<double[]> pointList = new LinkedList<double[]>();
	
	/**
	 * @return the numOfPoints
	 */
	@XmlAttribute( name = "num" )
	public int getNumOfPoints() {
		return numOfPoints;
	}

	/**
	 * @param numOfPoints the numOfPoints to set
	 */
	public void setNumOfPoints(int numOfPoints) {
		this.numOfPoints = numOfPoints;
	}
}```

Das ist jetzt mein letzter Testversuch, daher diese wirren Sichtbarkeiten... ich hatte davor schon alles andere Probiert aber das haut nicht hin.
Jetzt werfen wir einen Blick auf PointAdapter.java:
```package meshjoinery.geometry.beans;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class PointAdapter extends XmlAdapter<String, double[]> {
	@Override
	public double[] unmarshal(String v) throws Exception {
		//usually split lists at whitespace characters
		String[] arguments = v.split(" ");
		double[] points = new double[arguments.length];
		// System.out.println("-> " + v);
		for ( int i = 0; i < arguments.length; i++ )
			points** = Double.parseDouble( arguments** );
		
		return points;
	}

	@Override
	public String marshal(double[] v) throws Exception {
		String str = "";
		for ( int i = 0; i < v.length; i++ )
			str += Double.toString(v**) + " ";
		return str.substring(0, str.length()-1);
	}
}```

Bis hier hin geht alles gut... nur hat meine LinkedList<double[]> nach dem einlesen die Länge 0! Es wurden also keine Arrays in die Liste geschrieben...
Wenn ich die System.out.println in PointAdapter wieder rein nehme, sehe ich auch das die Methode brav für alle <p></p> ausgeführt wird.
Wenn ich statt der LinkedList<double[]> eine LinkedList<String> nehme und den adapter weglasse, ist die Liste ebenfalls vollständig.
Wenn ich für den Adapter nicht von String->double[] sondern von String->String umformen lasse und einfach jeden Wert in <p></p> in "ROFL" änder, dann funktioniert das auch... In jedem Eintrag der LinkedList<String> steht dann ROFL, genau 14290 mal...

Aber völlig egal was ich tue... er füllt diese verdammte Liste einfach nicht mit dem Double-Array...
Ich habs mit Double[] (statt double[]) versucht. Ich hab statt LinkedList alle möglichen Listen versuchen, einschließlich List<double[]>... Nichts funktioniert.

Mir gehen langsam die Ideen aus, die ich probieren könnte...
Mir wäre es auch wesentlich lieber, wenn ich mir die PointsBean sparen könnte...
In der PointSetBean hatte ich dann sowas zu stehen
```@XmlPath("points/@num")
public int num; // Attribute von <points/>

@XmlElementWrapper(name = "points")
@XmlElement(name = "p")
@XmlJavaTypeAdapter( PointAdapter.class )
public ArrayList<double[]> points = new ArrayList<double[]>(15000);```

Aber dann kam es zur oben erwähnten Fehlermeldung...
Ich verzweifel Langsam ,ich hoffe ihr könnt mir helfen. Wenn ihr mehr Code braucht kriegt ihr denn natürlich. Ich dachte nur es müsste reichen was ich euch hier gebe. Sonst wirds schnell unübersichtlich.
Ach ja einlesen tu ich das ganze sehr simpel...
```JVXBean jvx = JAXB.unmarshal(path.toFile(), JVXBean.class); // path ist der Pfad zur XML-Datei```
Und bei den ganzen Bean-Klassen liegt noch eine jaxb.properties im package worin steht:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Das brauchte ich um @XmlPath verwenden zu können, stand irgendwo im Netz.

Vielen Dank für eure Hilfe

Liebe Grüße
Highchiller

*** Edit ***

PS: Ein anderer Ansatz der klappt, wäre übrigens dieser hier. Die PointSetBean.java schaut jetzt so aus:
```package meshjoinery.geometry.beans;

import java.util.ArrayList;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlRootElement( name = "pointSet" )
@XmlAccessorType( XmlAccessType.FIELD )
public class PointSetBean {
	
	@XmlAttribute( name = "dim" )
	private int dimension;
	
	//@XmlPath("points/@num")
	private int numberOfPoints;
	
	@XmlElementWrapper(name = "points")
	@XmlElement(name = "p")
	@XmlJavaTypeAdapter( PointAdapter.class )
	private ArrayList<double[]> points;
	
	//@XmlElement( name = "points" )
	//private PointsBean points;
	
	public ArrayList<double[]> getPoints(){
		if ( points == null ) points = new ArrayList<double[]>(numberOfPoints);
		return points;
	}
	
	public void setPoints(ArrayList<double[]> points){
		this.points = points;
	}
	
	public int getNumberOfPoints(){
		return numberOfPoints;
	}
	
	public void setNumberOfPoints(int numberOfPoints){
		this.numberOfPoints = numberOfPoints;
	}
	
	/**
	 * @return the dimension
	 */
	public int getDimension() {
		return dimension;
	}

	/**
	 * @param dimension the dimension to set
	 */
	public void setDimension(int dimension) {
		this.dimension = dimension;
	}
}```
(hierfür musste ich die jaxb.properties Datei entfernen... damit ist es nicht mehr möglich das Attribut von points auszulesen... aber er füllt die Liste vollständig UND KORREKT mit allen Punkten als double[]).

Wenn ich hier 
```@PathXml( "points/@num" )```
wieder reinnehme UND die jaxb.properties datei wieder hinzufüge. Dann kommt die Fehlermeldung:

> javax.xml.bind.DataBindingException: javax.xml.bind.JAXBException: 
> Exception Description: XmlElementWrapper is only allowed on a collection or array property but [points] is not a collection or array property.


Hier die gesamter Fehlerstack, falls es hilft:
[SPOILER]javax.xml.bind.DataBindingException: javax.xml.bind.JAXBException: 
Exception Description: XmlElementWrapper is only allowed on a collection or array property but [points] is not a collection or array property.
 - with linked exception:
[Exception [EclipseLink-50015] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.JAXBException
Exception Description: XmlElementWrapper is only allowed on a collection or array property but [points] is not a collection or array property.]
	at javax.xml.bind.JAXB.unmarshal(JAXB.java:156)
	at meshjoinery.factory.JVXFactory.readJVX(JVXFactory.java:23)
	at meshjoinery.components.LoaderPanel$2.actionPerformed(LoaderPanel.java:52)
	at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
	at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2346)
	at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
	at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
	at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:290)
	at java.awt.Component.processMouseEvent(Component.java:6527)
	at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)
	at java.awt.Component.processEvent(Component.java:6292)
	at java.awt.Container.processEvent(Container.java:2234)
	at java.awt.Component.dispatchEventImpl(Component.java:4883)
	at java.awt.Container.dispatchEventImpl(Container.java:2292)
	at java.awt.Component.dispatchEvent(Component.java:4705)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4898)
	at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4533)
	at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4462)
	at java.awt.Container.dispatchEventImpl(Container.java:2278)
	at java.awt.Window.dispatchEventImpl(Window.java:2739)
	at java.awt.Component.dispatchEvent(Component.java:4705)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:746)
	at java.awt.EventQueue.access$400(EventQueue.java:97)
	at java.awt.EventQueue$3.run(EventQueue.java:697)
	at java.awt.EventQueue$3.run(EventQueue.java:691)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
	at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.awt.EventQueue$4.run(EventQueue.java:719)
	at java.awt.EventQueue$4.run(EventQueue.java:717)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:716)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Caused by: javax.xml.bind.JAXBException: 
Exception Description: XmlElementWrapper is only allowed on a collection or array property but [points] is not a collection or array property.
 - with linked exception:
[Exception [EclipseLink-50015] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.JAXBException
Exception Description: XmlElementWrapper is only allowed on a collection or array property but [points] is not a collection or array property.]
	at org.eclipse.persistence.jaxb.JAXBContext$TypeMappingInfoInput.createContextState(JAXBContext.java:1021)
	at org.eclipse.persistence.jaxb.JAXBContext.<init>(JAXBContext.java:174)
	at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:165)
	at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:152)
	at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:112)
	at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:102)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:247)
	at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:234)
	at javax.xml.bind.ContextFinder.find(ContextFinder.java:390)
	at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:641)
	at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:584)
	at javax.xml.bind.JAXB$Cache.<init>(JAXB.java:112)
	at javax.xml.bind.JAXB.getContext(JAXB.java:139)
	at javax.xml.bind.JAXB.unmarshal(JAXB.java:153)
	... 39 more
Caused by: Exception [EclipseLink-50015] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.JAXBException
Exception Description: XmlElementWrapper is only allowed on a collection or array property but [points] is not a collection or array property.
	at org.eclipse.persistence.exceptions.JAXBException.invalidElementWrapper(JAXBException.java:187)
	at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.finalizeProperties(AnnotationsProcessor.java:983)
	at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.processClassesAndProperties(AnnotationsProcessor.java:282)
	at org.eclipse.persistence.jaxb.compiler.Generator.<init>(Generator.java:150)
	at org.eclipse.persistence.jaxb.JAXBContext$TypeMappingInfoInput.createContextState(JAXBContext.java:1017)
	... 56 more[/SPOILER]

Also irgendwas ist einfach mal kaputt -.-

wie stabil ist den das XML schon? Ist eine Änderung an der XML-Stuktur noch akzeptabel?
[XML]











[/XML]Das könnte JaxB ohne gefrickel umwandeln.

bye
TT

Naja das Problem ist, dass ich die XML als Dateiausgabe von einem anderen Programm bekomme, auf dieses hab ich jedoch keinen Zugriff.
Also wenn ich nicht vorher per Hand in Java die Datei umschreiben will (und ich denke das wäre blöd) muss ich mit dem Format leben :confused:

JAXB ist doch irgendwie overkill - warum liest du das nicht einfach in ein DOM, oder einfachst mit SAX/Stax aus, wenn die Datei so simpel ist?

Na in der Datei stehen selbstverständlich noch eine ganze reihe weiterer Informationen.
Das ist quasi eine 3D-Mesh Datei mit Informationen á la Wavefront Object datei…

Zusätzlich kommen noch Vectoren dazu, MatchingSets etc.
Ich hab das nur auf das simple Beispiel runtergebrochen weil bereits hier der Fehler fliegt.

Gibts da kein Schema oder eine DTD dazu?

Ja schon, damit hatte ich auch Probleme, daher hatte ich das einfach auskommentiert. Die DTD findest du hier:
http://www.javaview.de/rsrc/jvx.dtd

Verzweiflungstat: Klassen mit JAXB generieren

mal xjc mit der option -dtd aufrufen? Wird zwar nicht funktionieren, aber einen Versuch ist es Wert…

Wenn ich nochmal auf die Fehlermeldung schaue könnte sich noch mal ein Ansatzpunkt ergeben:

[quote=Highchiller]

XmlElementWrapper is only allowed on a collection or array property but [points] is not a collection or array property.

[/quote]Und da hat JaxB recht. Die Collection ist nämlich <p>

bye
TT

Hä? Vielleicht ist die Namenwahl unglücklich gewählt.
Wieso sollte der XmlElementWrapper denn selber eine Collection/Array sein… es geht doch darum, dass der innere Part eine Collection/Array ist

Wenn ich dich richtig verstehe, kann ich also eine Struktur wie diese

[QUOTE=Highchiller][XML]

0.309469 -0.921392 0.450065


-0.246077 0.582705 0.060732



[/XML]
[/QUOTE]

nicht als

@XmlElement( name = "p" )
ArrayList<double[]> listofPoints;

verpacken?

Ich habe selbst noch nie mit JAXB gearbeitet, aber ich würde sagen: Nein. Grund ist das Attribut „num“ im points-Element. Wie soll das mit einem Wrapper „ArrayList“ abgedeckt werden? Das wird der Grund sein, warum JAXB sagt, dass es sich bei [points] nicht (nur) um eine Collection handelt.

Klingt plausibel. Allerdings erklärt das nicht das Eingangs erwähnte Problem. Da das ja nicht funktionierte hatte ich versucht stupide eine extra Klasse für “points” zu schreiben. Damit kann ich dann das Attribute auslesen. Allerdings funktioniert dann der XmlJavaTypeAdapter nicht…

Problem verlagert, aber nicht behoben.