A forma mais simples de evitar o loop é usando o próprio construtor no setter.
O exemplo foi tirado de: https://www.devmedia.com.br/introducao-a-jaxb-2/11547
Eu apenas criei mais um atributo: contatoAnterior.
E alterei o teste para provocar o ciclo:
contato.setContatoAnterior( contato );
Com o setter original ( this.contatoAnterior = contatoAnterior; ) deverão tomar o erro:
Exception in thread "main" javax.xml.bind.MarshalException
- with linked exception:
[com.sun.istack.internal.SAXException2: Foi detectado um ciclo no gráfico do objeto. Isso causará XML profundo infinitamente: contato.Contato@2d98a335 -> contato.Contato@2d98a335]
Com o setter modificado para usar o contrutor. O retorno fica bom.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<contato>
<contatoAnterior>
<endereco>
<bairro>Centro LADRÃO</bairro>
<cep>20000-000 SEM-VERGONHA</cep>
<cidade>Rio de Janeiro SAFADO</cidade>
<logradouro>Rua Moraes PILANTRA</logradouro>
<numero>40 VIGARISTA</numero>
</endereco>
<idade>34</idade>
<nome>Marco Maciel</nome>
<sexo>M</sexo>
</contatoAnterior>
<endereco>
<bairro>Centro</bairro>
<cep>20000-000</cep>
<cidade>Rio de Janeiro</cidade>
<logradouro>Rua Moraes</logradouro>
<numero>40</numero>
</endereco>
<idade>34</idade>
<nome>Marco Maciel</nome>
<sexo>M</sexo>
</contato>
------------------------------------------------------------------
package contato;
import javax.xml.bind.annotation.*;
@XmlRootElementpublic class Contato {
private String nome; private String sexo;
private int idade; private Endereco endereco;
private Contato contatoAnterior;
public Contato() {}
public Contato(String nome, String sexo
, int idade, Endereco endereco) {
this.nome = nome;
this.sexo = sexo;
this.idade = idade;
this.endereco = endereco;
}
// outros G e S
public Contato getContatoAnterior() {
return contatoAnterior; }
public void setContatoAnterior(Contato contatoAnterior) {
//this.contatoAnterior = contatoAnterior; // original
this.contatoAnterior = new Contato( contatoAnterior.getNome(),
contatoAnterior.getSexo(), contatoAnterior.getIdade(),
contatoAnterior.getEndereco());
}
}
------------------------------------------------------------------
package contato;
/* Os imports foram omitidos para não ocupar espaço */
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.HashMap;
public class JaxbTeste {
public static void main(String args[]) throws JAXBException,
FileNotFoundException {
Endereco endereco = new Endereco("Rua Moraes", 40, "Centro"
,"Rio de Janeiro", "20000-000");
Contato contato = new Contato("Marco Maciel", "M",34, endereco);
contato.setContatoAnterior( contato );
JAXBContext context = JAXBContext.newInstance(Contato.class);
//saída 1 – console
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
m.marshal(contato, System.out);
}
}