2017-09-13 15 views
0

Je teste marshalling et unmarshalling les objets Java suivants:JAXB Collection unmarshal (Set)

classe Cadre:

@XmlRootElement (name = "framework") 
@XmlAccessorType(XmlAccessType.FIELD) 
@Entity 
public class Framework implements Comparable<Framework>, Serializable { 
    private static final long serialVersionUID = 1L; 
    @XmlTransient 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 
    private String frameworkName; 
    private String frameworkVersion; 
    private String frameworkDescription; 
    @XmlElementWrapper(name = "framework-domains") 
    private Set<FrameworkDomain> frameworkDomainList = new HashSet<>(); 
    @XmlElementWrapper(name = "framework-comments") 
    private Set<Comment> comments = new HashSet<>(); 

(ne contient que des apporteurs, setters et un nuber de fonctions sans annotation supplémentaire)

classe domaine:

@XmlRootElement(name = "domain") 
@XmlAccessorType(XmlAccessType.FIELD) 
@Entity 
public class FrameworkDomain implements Comparable<FrameworkDomain>, Serializable { 

    private static final long serialVersionUID = 1L; 
    @XmlTransient 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 
    private String domainName; 
    private String domainDescription; 
    @XmlElementWrapper(name = "domain-requirements") 
    private Set<Requirement> domainRequirements = new HashSet<>(); 
    @XmlElementWrapper(name = "domain-comments") 
    private Set<Comment> domainComments = new HashSet<>(); 

Exigence cla ss:

@XmlRootElement(name = "requirement") 
@XmlAccessorType(XmlAccessType.FIELD) 
@Entity 
public class Requirement implements Comparable<Requirement>, Serializable { 

    private static final long serialVersionUID = 1L; 
    @XmlTransient 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 
    private String requirementName; 
    private String requirementDescription; 
    private String requirementGuidance; 
    @XmlElementWrapper(name = "sub-requirements") 
    private Set<Requirement> requirementSubrequirementList = new HashSet<>(); 
    @XmlElementWrapper(name = "testing-procedures") 
    private Set<TestingProcedure> requirementTestingProceduresList = new HashSet<>(); 
    @XmlElementWrapper(name = "requirement-comments") 
    private Set<Comment> comments = new HashSet<>(); 

Marshalling et le code unmarshaling:

public static String exportFramework(Framework f) { 
    java.io.StringWriter s = new java.io.StringWriter(); 
    try { 
     JAXBContext jc = JAXBContext.newInstance(Framework.class); 

     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8"); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 

     marshaller.marshal(f, s); 
    } catch (Exception ex) { 
     ex.printStackTrace(); 
    } 

    return s.toString(); 
} 

public static Framework importFramework(java.io.InputStream xml) { 
    intelicompliance.model.Framework f = null; 

    try { 
     JAXBContext jc = JAXBContext.newInstance(Framework.class); 

     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     f = (intelicompliance.model.Framework) unmarshaller.unmarshal(xml); 
    } catch (JAXBException ex) { 
     ex.printStackTrace(); 
    } 

    return f; 
} 

Quand je Marshal un objet que je l'ai créé, il génère le code XML suivant:

<?xml version="1.0" encoding="utf-8" standalone="yes"?> 
<framework> 
    <frameworkName>PCI DSS</frameworkName> 
    <frameworkVersion>3.3</frameworkVersion> 
    <frameworkDescription>The Payment Card Industry Data Security Standard (PCI DSS) is a proprietary information security standard for organizations that handle branded credit cards from the major card schemes including Visa, MasterCard, American Express, Discover, and JCB.</frameworkDescription> 
    <framework-domains> 
     <frameworkDomainList> 
      <domainName>Domain 1a</domainName> 
      <domainDescription>Build and Maintain a Secure Network and Systems</domainDescription> 
      <domain-requirements></domain-requirements> 
      <domain-comments></domain-comments> 
     </frameworkDomainList> 
     <frameworkDomainList> 
      <domainName>Domain 2a</domainName> 
      <domainDescription>Protect Cardholder Data</domainDescription> 
      <domain-requirements/> 
      <domain-comments/> 
     </frameworkDomainList> 
     <frameworkDomainList> 
      <domainName>Domain 3a</domainName> 
      <domainDescription>Maintain a Vulnerability Management Program</domainDescription> 
      <domain-requirements/> 
      <domain-comments/> 
     </frameworkDomainList> 
     <frameworkDomainList> 
      <domainName>Domain 4a</domainName> 
      <domainDescription>Implement Strong Access Control Measures</domainDescription> 
      <domain-requirements/> 
      <domain-comments/> 
     </frameworkDomainList> 
     <frameworkDomainList> 
      <domainName>Domain 5a</domainName> 
      <domainDescription>Regularly Monitor and Test Networks</domainDescription> 
      <domain-requirements/> 
      <domain-comments/> 
     </frameworkDomainList> 
     <frameworkDomainList> 
      <domainName>Domain 6a</domainName> 
      <domainDescription>Maintain an Information Security Policy</domainDescription> 
      <domain-requirements/> 
      <domain-comments/> 
     </frameworkDomainList> 
    </framework-domains> 
    <framework-comments/> 
</framework> 

... ce qui est exactement ce que Je m'attends à. Cependant, lorsque j'essaie de reconvertir le XML dans l'objet, seul l'un des domaines est inclus dans le Set - c'est-à-dire que le processus d'importation (unmarshalling) ignore les nœuds XML après le premier.

Est-ce que quelqu'un a une idée pourquoi? Ou, qu'est-ce que je fais mal?

MISE À JOUR J'ai fait quelques progrès en changeant:

private Set<FrameworkDomain> frameworkDomainList = new HashSet<>(); 

à:

private List<FrameworkDomain> frameworkDomainList = new LinkedList<>(); 

qui importe maintenant tous les éléments enfants comme prévu. Cependant, je préfère vraiment utiliser Set.

Est-ce que JAXB traite les ensembles différents des listes?

+0

Avez-vous correctement défini les méthodes hashCode() dans vos objets? –

+0

Vous ne savez pas ce que vous entendez par "correctement" ... voici le code: @Override public int hashCode() { int hash = 0; hash + = (id! = Null? Id.hashCode(): 0); hachage de retour; } – JohnMarkh

Répondre

0

En fonction de votre réponse à ma question:

Ce que je voulais dire est bien que vous assuré que tous les objets qui ne sont pas les mêmes renverra un hachage différent. Votre problème vient du fait que chaque objet que vous avez unmarshalling a le même hashCode, donc votre set pense que tous les éléments sont égaux, et n'en gardent qu'un (le dernier JAXB traite, incidemment le premier).

Vous devriez être en mesure de confirmer ce comportement en ajoutant dans un HashSet vos objets sans ID, seul le dernier doit être conservé.

Il explique également pourquoi votre liste est remplie lorsque vous passez à une liste liée. Utilisez une méthode hashCode différente ou regroupez les ID pour résoudre votre problème. N'oubliez pas que vous devez toujours remplacer la méthode equals() par la méthode hashCode() et que a.equals (b) et a.hashCode == b.hashCode donnent toujours les mêmes résultats.

+0

Vous, mon ami, est un érudit et messieurs! Vous avez identifié le problème et la solution suggérée! – JohnMarkh