2012-03-09 11 views
5

Quindi sto lavorando su un'API dati RESTful usando Java, Hibernate, annotazioni JPA, annotazioni JAX-RS, annotazioni JAXB, Jersey e il parser JSON Jackson .Come aggirare l'incapacità di Jackson di gestire riferimenti diretti nei bean JPA

Dopo aver provato varie configurazioni delle notazioni MAPPING e NATURAL JSON fornite da Jersey, alla fine ho deciso di utilizzare il parser Jackson JSON. Jackson sarebbe perfetto tranne per questo problema ...

Il problema che ho riscontrato è che Jackson non funziona con le annotazioni JAXB, "@XmlID" e "@XmlIDREF", che uso per indicare la mia entità relazioni, e anche se "@JsonBackReference" e "@JsonManagedReference" aiutano con questo. La combinazione sembra crollare quando si tratta di proprietà dirette di autoreferenzialità.

Sembra che sarebbe un problema abbastanza comune. Come mai qualcuno di voi ha aggirato questa limitazione con Jackson?

Con il mio POJO come ...

@XmlRootElement 
public class Employee implements Serializable { 
    private Date lastUpdatedOn; 
    private Employee lastUpdatedBy; 
    private Integer empId; 

    @JoinColumn(nullable=false) 
    @OneToOne 
    @XmlIDREF 
    public Employee getLastUpdatedBy() { 
     return createdBy; 
    } 
    public void setLastUpdatedBy(Employee lastUpdatedBy) { 
     this.lastUpdatedBy = lastUpdatedBy; 
    } 

    @Temporal(TemporalType.TIMESTAMP) 
    public Date getLastUpdatedOn() { 
     return createdOn; 
    } 
    public void setLastUpdatedOn(Date lastUpdatedOn) { 
     this.lastUpdatedOn = lastUpdatedOn; 
    } 
    @XmlID 
    @XmlJavaTypeAdapter(IntegerAdapter.class) 
    public Integer getEmpId() { 
     return empId; 
    } 
    public void setEmpId(Integer empId) { 
     this.empId = empId; 
    } 
} 

... e il seguente EmployeeResource ...

@Path("/Employees") 
public class EmployeeResource { 
    private List<Employee> employees; 

    public List<Employee> getEmployees() { 
    return employees; 
    } 
    public void setEmployees(List<Employee> employees) { 
    this.employees = employees; 
    } 

    @GET 
    @Path("/{empId}") 
    public Response getEmployees(
    @Context UriInfo ui 
    , @PathParam("id") Integer empId 
) { 
    this.employees = HibernateUtil.pagedQuery(
     Employee.class 
     , new ArrayList() { 
     Restrictions.eq("empId",empId) 
     } 
    ); 
    return Response.ok(this).build(); 
    } 
} 

mia risorsa JAX-RS produrrà il seguente errore

org.codehaus.jackson.map.JsonMappingException: Direct self-reference leading to cycle (through reference chain: resources.EmployeeResource["employees"]->java.util.ArrayList[0]->entities.Employee["lastUpdatedBy"]) 

... ma voglio produrre ...

{ 
    "employees" : [ { 
    "lastUpdatedOn" : 1331149770737, 
    "lastUpdatedBy" : 10150, 
    "empId" : 10150, 
    } ], 
} 

Grazie in anticipo a tutti!

NOTE:

  1. uso l'IntegerAdapter.class per convertirlo in una stringa in modo che funzioni con l'annotazione @XmlID.
  2. Le classi Employee e EmployeeResource descritte in precedenza sono solo versioni abbreviate della mia implementazione effettiva, ma rappresentano la parte della mia implementazione che è rilevante per questo problema di autoreferenziale diretto.

EDIT # 1 2012/03/10 Mi dispiace, nella mia prima versione di questa domanda mi ero confuso tra la versione che ho con la notazione naturale di Jersey vs la versione che ho in esecuzione con Jackson. Ho rivisto la mia domanda per riflettere più accuratamente il problema diretto autoreferenziale che ho con Jackson.

+0

Penso che la tua domanda non sia pertinente a '@ XmlID' così com'è, ma alle basi JSON. JSON non supporta i tipi, quindi "" 10150 "' (stringa) e '10150' (numeri interi, ma non supportati) sono" uguali ". –

+2

Non sarei d'accordo. JSON ha una comprensione di tipi come Object, Array, String e number, www.json.org. – hypno7oad

+0

Mi dispiace male. Quello di cui hai bisogno credo sia il convertitore da 'Date' a' int'. Vedere l'esempio [qui] (http://blog.seyfi.net/2010/03/how-to-control-date-formatting-when.html). –

risposta

4

Jackson 1.x non ha un supporto specifico per la risoluzione dei riferimenti ciclici, ma esiste un supporto per la gestione delle dipendenze stile genitore/figlio: this il post di blog ha più informazioni.

Jackson 2.0 supporta la gestione di oggetti/riferimenti arbitrari, utilizzando la nuova annotazione @JsonIdentityInfo, quindi forse potrebbe essere utilizzata per risolvere il problema. La versione ufficiale 2.0 non è ancora disponibile, ma i candidati al rilascio (l'ultimo di RC2) sono, nel caso in cui volessi dare un'occhiata. Non sono sicuro se gestirà il tuo problema, ma forse sarebbe d'aiuto.

MODIFICA: In realtà, il modulo di annotazione Jackson JAXB supporterà @XmlID/@XmlIDREF per 2.0.0 - questo è stato appena implementato, vedere here.

+0

Grazie per il link. Daremo un'occhiata a RC2. Anche se è un po 'deludente che non possano usare le annotazioni JAXB per questo molto simile a Jersey. – hypno7oad

+0

Le annotazioni JAXB sono specifiche per bit XML, quindi per Jackson sono secondarie - supportate, ma devono essere adattate per funzionare tramite meccanismi nativi. FWIW, ora c'è questo: [https://github.com/FasterXML/jackson-module-jaxb-annotations/issues/2] che tiene traccia delle possibilità di implementare le annotazioni JAXB ... – StaxMan

+0

Grazie @Staxman, terrò un occhio sul thread github. – hypno7oad

Problemi correlati