web-dev-qa-db-fra.com

Comment utiliser spring to marshal et unmarshal xml?

J'ai un projet de démarrage de printemps. J'ai quelques xsds dans mon projet. J'ai généré les classes en utilisant maven-jaxb2-plugin. J'ai utilisé this tutorial pour faire fonctionner un exemple d'application d'amorçage printanier.

import org.kaushik.xsds.XOBJECT;

@SpringBootApplication
public class JaxbExample2Application {

public static void main(String[] args) {
    //SpringApplication.run(JaxbExample2Application.class, args);
    XOBJECT xObject = new XOBJECT('a',1,2);

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

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(xObject, System.out);

    } catch (PropertyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (JAXBException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
 }
}

Mais ce qui me préoccupe, c’est que j’ai besoin de mapper toutes les classes jaxb du schéma. De plus, y at-il quelque chose au printemps que je peux utiliser pour me faciliter la tâche. J'ai examiné le projet Spring OXM mais le contexte de l'application était configuré en xml. Est-ce que la botte de printemps a tout ce que je peux utiliser hors de la boîte? Tous les exemples seront utiles.

Modifier

J'ai essayé la réponse de xerx593 et j'ai fait un test simple en utilisant la méthode principale 

    JaxbHelper jaxbHelper = new JaxbHelper();
    Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
    marshaller.setClassesToBeBound(XOBJECT.class);
    jaxbHelper.setMarshaller(marshaller);
    XOBJECT xOBJECT= (PurchaseOrder)jaxbHelper.load(new StreamSource(new FileInputStream("src/main/resources/PurchaseOrder.xml")));
    System.out.println(xOBJECT.getShipTo().getName());

Cela a fonctionné parfaitement bien. Maintenant, j'ai juste besoin de le brancher avec une botte à ressort.

9

OXM est définitivement le droit pour vous!

Une configuration Java simple d'un Jaxb2Marshaller ressemblerait à ceci:

//...
import Java.util.HashMap;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
//...

@Configuration
public MyConfigClass {
    @Bean
    public Jaxb2Marshaller jaxb2Marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setClassesToBeBound(new Class[]{
           //all the classes the context needs to know about
           org.kaushik.xsds.All.class,
           org.kaushik.xsds.Of.class,
           org.kaushik.xsds.Your.class,
           org.kaushik.xsds.Classes.class
        }); //"alternatively" setContextPath(<jaxb.context>), 

        marshaller.setMarshallerProperties(new HashMap<String, Object>() {{
          put(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT, true);
        }});

        return marshaller;
    }
}

Dans votre classe Application/Service, vous pourriez aborder comme ceci:

import Java.io.InputStream;
import Java.io.StringWriter;
import javax.xml.bind.JAXBException;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;  

@Component
public MyMarshallerWrapper {
   // you would rather:
   @Autowired
   private Jaxb2Marshaller  marshaller;
   // than:
   // JAXBContext jc = JAXBContext.newInstance(User.class);
   // Marshaller marshaller = jc.createMarshaller();

   // marshalls one object (of your bound classes) into a String.
   public <T> String marshallXml(final T obj) throws JAXBException {
      StringWriter sw = new StringWriter();
      Result result = new StreamResult(sw);
      marshaller.marshal(obj, result);
      return sw.toString();
   }

   // (tries to) unmarshall(s) an InputStream to the desired object.
   @SuppressWarnings("unchecked")
   public <T> T unmarshallXml(final InputStream xml) throws JAXBException {
      return (T) marshaller.unmarshal(new StreamSource(xml));
   }
}

Voir Jaxb2Marshaller-javadoc , et un Answer

15
xerx593

Si vous voulez juste serializing/deserializing bean avec XML. Je pense que jackson fasterxml est un bon choix:

ObjectMapper xmlMapper = new XmlMapper();
String xml = xmlMapper.writeValueAsString(new Simple());  // serializing

Simple value = xmlMapper.readValue("<Simple><x>1</x><y>2</y></Simple>",
     Simple.class); // deserializing

maven:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

Voir: https://github.com/FasterXML/jackson-dataformat-xml

7
bluearrow

Spring BOOT est très intelligent et peut comprendre ce dont vous avez besoin avec un peu d'aide.

Pour que le tri/marshalling XML fonctionne, il suffit d'ajouter @XmlRootElement à la classe annotations et @XmlElement aux champs sans getter et la classe cible sera sérialisée/désérialisée automatiquement.

Voici l'exemple de DTO

package com.exmaple;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import Java.io.Serializable;
import Java.util.Date;
import Java.util.Random;

@AllArgsConstructor
@NoArgsConstructor
@ToString
@Setter
@XmlRootElement
public class Contact implements Serializable {
    @XmlElement
    private Long id;

    @XmlElement
    private int version;

    @Getter private String firstName;

    @XmlElement
    private String lastName;

    @XmlElement
    private Date birthDate;

    public static Contact randomContact() {
        Random random = new Random();
        return new Contact(random.nextLong(), random.nextInt(), "name-" + random.nextLong(), "surname-" + random.nextLong(), new Date());
    }
}

Et le contrôleur:

package com.exmaple;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping(value="/contact")
public class ContactController {
    final Logger logger = LoggerFactory.getLogger(ContactController.class);

    @RequestMapping("/random")
    @ResponseBody
    public Contact randomContact() {
        return Contact.randomContact();
    }

    @RequestMapping(value = "/edit", method = RequestMethod.POST)
    @ResponseBody
    public Contact editContact(@RequestBody Contact contact) {
        logger.info("Received contact: {}", contact);
        contact.setFirstName(contact.getFirstName() + "-EDITED");
        return contact;
    }
}

Vous pouvez voir un exemple de code complet ici: https://github.com/sergpank/spring-boot-xml

Toutes les questions sont les bienvenues.

4
sergpank

Vous pouvez utiliser StringSource/StringResult pour lire/lire le code source XML avec spring

 @Autowired
    Jaxb2Marshaller jaxb2Marshaller;

    @Override
    public Service parseXmlRequest(@NonNull String xmlRequest) {
        return (Service) jaxb2Marshaller.unmarshal(new StringSource(xmlRequest));
    }

    @Override
    public String prepareXmlResponse(@NonNull Service xmlResponse) {
        StringResult stringResult = new StringResult();
        jaxb2Marshaller.marshal(xmlResponse, stringResult);
        return stringResult.toString();
    }
0
Mohamed.Abdo