JAXB: A cycle is detected in the object graph. This will cause infinitely deep XML

RungetSvohu

Bekanntes Mitglied
Hallo Leute,

kann mir einer erklären, wieso es hier zu einer javax.xml.bind.MarshalException kommt, die meint einen cycle entdeckt zu haben?

TimeOfDay-Class:
Java:
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class TimeOfDay extends GregorianCalendar {

	private static final long serialVersionUID = 1L;
	private final GregorianCalendar timestamp;

	public TimeOfDay() {
		super();
		timestamp = this;
		set(YEAR, 2012);
		set(MONTH, 0);
		set(DAY_OF_MONTH, 1);
		set(SECOND, 0);
		set(MILLISECOND, 0);
	}

	public TimeOfDay(int hour, int minute) {
		this();
		setTime(hour, minute);
	}

	public GregorianCalendar getTimestamp() {
		return timestamp;
	}

	public void setTimestamp(GregorianCalendar timestamp) {
		setTime(timestamp.get(HOUR_OF_DAY), timestamp.get(MINUTE));
	}

	@Override
	public TimeOfDay clone() {
		return new TimeOfDay(getHour(), getMinute());
	}

	public void setTime(int hour, int minute) {
		set(HOUR_OF_DAY, hour);
		set(MINUTE, minute);
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		SimpleDateFormat format = new SimpleDateFormat("kk:mm");
		sb.append(format.format(getTime()));
		sb.append(" Uhr");
		return sb.toString();
	}

	public int getHour() {
		return get(HOUR_OF_DAY);
	}

	public int getMinute() {
		return get(MINUTE);
	}

}

Ausgeführt wird:

Java:
	public static void main(String[] args) {
		TimeOfDay test = new TimeOfDay();

		File testFile = new File("test.xml");
		JAXBContext context;
		try {
			context = JAXBContext.newInstance(TimeOfDay.class);
			Marshaller m = context.createMarshaller();
			m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
			FileWriter writer = new FileWriter(testFile);
			m.marshal(test, writer);
			writer.close();
		} catch (final JAXBException e) {
			e.printStackTrace();
		} catch (final IOException e) {
			e.printStackTrace();
		}

	}

Vielen Dank!
 
ein TimeOfDay enthält ein Attribut timestamp, darin ist wieder dasselbe TimeOfDay, also wieder ein Attribut timestamp usw.,
das ist doch naheliegend,

wozu brauchst du das Attribut? in der getTimestamp()-Methode kannst du doch direkt this zurückgeben


edit:
@XmlTransient
könnte evtl. helfen
 
Zuletzt bearbeitet von einem Moderator:
Wahrscheinlich wegen dem hier:
Java:
    private final GregorianCalendar timestamp;
Die Variable ist unnötig, weil Deine Klasse von GregorianCalendar ableitet. Und weiter unten setzt Du sie auf
Code:
this
. Das könnte dazu führen, dass im XML das Element sich selbst als Kind hat.
 
Wahrscheinlich wegen dem hier:
Java:
    private final GregorianCalendar timestamp;
Die Variable ist unnötig, weil Deine Klasse von GregorianCalendar ableitet. Und weiter unten setzt Du sie auf
Code:
this
. Das könnte dazu führen, dass im XML das Element sich selbst als Kind hat.

Ah, danke. Nun kommt kein Fehler mehr, dafür sieht die XML-Datei so aus:

Code:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<timeOfDay/>

Also die Zeit selbst geht verloren. Woran liegt das?

PS: Die Klasse habe ich vor zwei Jahren geschrieben, damals lief es noch, aber heute bekommt er Probleme. Die scheinen da bei JAXB irgendetwas geändert zu haben.

Danke für die Hilfe!
 
Also die Zeit selbst geht verloren. Woran liegt das?
Da hört es mit meinen JAXB-Kenntnissen leider auf. Ich weiß nicht, inwieweit JAXB implizit getter mappt. Falls garnicht, müsstest Du die getter evtl. überschreiben, um über diesen die enstpr. JAXB-Annotationen setzen zu können.
 
> Also die Zeit selbst geht verloren. Woran liegt das?

was läßt dich glauben, dass es gehen können?
wieso sollte die API überhaupt irgendwas tun? da muss es doch eine grundsätzliche Annahme geben,
hast du das je erfolgreich gesehen, z.B. Beispiele in Tutorials?

im Zweifel auch immer genau an diese halten, ich habe jetzt die dumpfe Vermutung/ Erinnerung dass es mit dem Beans-Standard zu tun haben könnte:
nur Attribute x, zu denen es setX()-, getX()-Methoden gibt, werden ausgelesen,
das Interne GregorianCalendar fällt nicht darunter,

evtl. ist Vererbung generell übel dran, also Oberklassen ignoriert

vielleicht sind irgendwo exakte Spezifikationen nachzulesen
 
Habe das Problem gelöst, so klappt es nun:

Java:
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class TimeOfDay extends GregorianCalendar {

	private static final long serialVersionUID = 1L;

	private final GregorianCalendar timestamp;

	public TimeOfDay() {
		super();
		set(YEAR, 2012);
		set(MONTH, 0);
		set(DAY_OF_MONTH, 1);
		set(SECOND, 0);
		set(MILLISECOND, 0);
		timestamp = new GregorianCalendar();
		timestamp.setTime(getTime());
	}

	public TimeOfDay(int hour, int minute) {
		this();
		setTime(hour, minute);
	}

	public GregorianCalendar getTimestamp() {
		return timestamp;
	}

	public void setTimestamp(GregorianCalendar timestamp) {
		setTime(timestamp.get(HOUR_OF_DAY), timestamp.get(MINUTE));
	}

	@Override
	public TimeOfDay clone() {
		return new TimeOfDay(getHour(), getMinute());
	}

	public void setTime(int hour, int minute) {
		set(HOUR_OF_DAY, hour);
		set(MINUTE, minute);
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		SimpleDateFormat format = new SimpleDateFormat("kk:mm");
		sb.append(format.format(getTime()));
		sb.append(" Uhr");
		return sb.toString();
	}

	public int getHour() {
		return get(HOUR_OF_DAY);
	}

	public int getMinute() {
		return get(MINUTE);
	}

}
 

Neue Themen


Zurück
Oben