Stream error when invoking a REST service in Spring MVC with two javascript objects

1

Greetings estoyr trying to pass as parameter two JSON objects to a REST method that is in a rest API in Spring MVC , I'm using a service type factory in AngularJS to make the call to the method.

The server responds with an error 500 with this message

Could not read document: Stream closed; nested exception is java.io.IOException: Stream closed

The method worked correctly when passed a single object of type JSON, but to modify it so that it received two objects of type JSON caused that it passes this error.

This is my factory type service in AngularJS here I pass two parameters of type JSON one called client and another contact when the client only passes the method if it worked.

createCliente: function (cliente, contacto) {
                            return $http.post('http://localhost:8080/MySpringMVCApp/cliente/', cliente, contacto)
                                    .then(
                                            function (response) {
                                                console.log('Inside Cliente-Servicio createCliente');

                                                return response.data;
                                            },
                                            function (errResponse) {
                                                console.error('Error ' + errResponse);
                                                return $q.reject(errResponse);
                                            }
                                    );
                        }

here is the backend method in spring, adapt it to receive two parameros

 @RequestMapping(value = "/cliente/", method = RequestMethod.POST)
public ResponseEntity<Void> createCliente(@RequestBody Cliente cliente, @RequestBody Contacto contacto, UriComponentsBuilder ucBuilder) {


    HttpHeaders headers = new HttpHeaders();
    headers.setLocation(ucBuilder.path("/cliente/{id}").buildAndExpand(cliente.getIdCliente()).toUri());
    System.out.println("headers vale " + headers);
    clienteDAO.insertarCliente(cliente);
    Integer ultimoIdCliente = clienteDAO.buscarUltimoIdClienteEnBDporNombreCliente(cliente.getNombre());
    contactoDAO.insertarContactoCliente(contacto, ultimoIdCliente);

    return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}

but the server returns this error Could not read document: Stream closed; nested exception is java.io.IOException: Stream closed

EDIT:  Check and the error was that you can only pass a variable of type @RequestBody but I'm not sure if it's true, so change the controller as follows

@RequestMapping(value = "/cliente/", method = RequestMethod.POST)
    public ResponseEntity<Void> createCliente(@RequestBody Cliente cliente, String contactoJSON, UriComponentsBuilder ucBuilder) {
Contacto contactoParseado = new ObjectMapper().readValue(contacto, Contacto.class);
}

And after I have the JSON contact I try to parse the object with a libra, the problem is that contact JSON arrives null it arrives without any value and gives me the exception nullpointer exception, how could this json String pass to the controller for then parsing it to my object type

I'm calling the backend method like that from angulajs

$http.post('http://localhost:8080/MySpringMVCApp/cliente/', cliente, contacto)

but I do not see what the error would be

EDIT2 Edit the factory method in the following way

createCliente: function (cliente, contacto) {
                    var data = {
                        "cliente": cliente,
                        "contacto": contacto
                    };

                    return $http.post('http://localhost:8080/SpringMVCTemplateAnn/cliente/', data)
                            .then(
                             //resto codigo

and that factory service I pass the following objects

var clienteJSON = {
                    idCliente: 0,
                    nombre: cliente.nombre,
                    alias: cliente.alias,
                    listaContacto: null,
                    listaPersonaContacto: null
                };
 var contactoJSON = {
                    idContacto: 0,
                    idCliente: 0,
                    idPersonaContacto: 0,
                    ubicacion: contacto.ubicacion,
                    numeroTelefono: contacto.numeroTelefono,
                    email: contacto.email,
                    paginaWeb: contacto.paginaWeb,
                    rif: contacto.rif
                };

the objects are filled satisfactorily with the frontend data

backend method

@RequestMapping(value = "/cliente/", method = RequestMethod.POST)
public ResponseEntity<Void> createCliente(@RequestBody Map<String, String> datos, UriComponentsBuilder ucBuilder) {

    System.out.println("contacto JSON vale: " + datos);
    System.out.println("cliente JSON vale: " + datos);

    HttpHeaders headers = new HttpHeaders();
    try {
        Cliente clienteParseado = new ObjectMapper().readValue(datos.get("cliente"), Cliente.class);
        Contacto contactoParseado = new ObjectMapper().readValue(datos.get("contacto"), Contacto.class);

These are the Json objects that the backend method receives

my contact json

({idContacto:0, idCliente:0, idPersonaContacto:0, ubicacion:"contactoUbicacionValor", numeroTelefono:"contactoTelefonoValor", email:"contactoEmailValor", paginaWeb:"contactoPagiaValor", rif:"contactoRifValor"})

my client json

({idCliente:0, nombre:"nombreDelClienteValor", alias:"AliasDelClienteValor", listaContacto:null, listaPersonaContacto:null})

and my Map

({cliente:{idCliente:0, nombre:"nombreDelClienteValor", alias:"AliasDelClienteValor", listaContacto:null, listaPersonaContacto:null}, contacto:{idContacto:0, idCliente:0, idPersonaContacto:0, ubicacion:"contactoUbicacionValor", numeroTelefono:"contactoTelefonoValor", email:"contactoEmailValor", paginaWeb:"contactoPagiaValor", rif:"contactoRifValor"}})

These are the classes of the objects in java

MI Class Customer Class

public class Cliente {

private Integer idCliente;
private String nombre;
private String alias;
private List<Contacto> listaContacto;
private List<PersonaContacto> listaPersonaContacto;

MY Class Contact

public class Contacto {

private Integer idContacto;
private Integer idCliente;
private Integer idPersonaContacto;
private String ubicacion;
private String tipo;
private String numeroTelefono;
private String email;
private String paginaWeb;
private String rif;

After having made the moifications the server gives me back this error

    Could not read document: Can not deserialize instance of java.lang.String out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@2f3ab7f1; line: 1, column: 2] (through reference chain: java.util.LinkedHashMap["cliente"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@2f3ab7f1; line: 1, column: 2] (through reference chain: java.util.LinkedHashMap["cliente"])

I suspect that it could be because my client class has attributes that are type List and when I set them to null when I assemble the object this could cause some error is my suspicion.

    
asked by Bill_Data23 31.05.2016 в 21:23
source

1 answer

1

You can not send two objects through a REST request. Spring will read the contents of 1 first and then close the stream of the body of the content of the request, so when it has to read the second object, since the stream is closed, it can not read it and this exception is issued. This is not a limitation of Spring, but something natural that can happen in any other technology even outside of Java.

If you need to send more information to the server, it would be best to send 1 single object that contains the information of your two or more entities, and server side separate them conveniently.

In case you want to pause the String objects manually from Spring, you can do so.

On the client's side:

createCliente: function (cliente, contacto) {
    var data = {
        "cliente" : cliente,
        "contacto" : contacto
    };
    return $http.post('http://localhost:8080/MySpringMVCApp/cliente/', data)
    //resto del código...
}

Server side:

@RequestMapping(value = "/cliente/", method = RequestMethod.POST)
public ResponseEntity<Void> createCliente(@RequestBody Map<String, String> datos, UriComponentsBuilder ucBuilder) {
    //esto es básico, debes mejorarlo
    ObjectMapper objectMapper = new ObjectMapper();
    Cliente cliente = objectMapper.readValue(datos.get("cliente"), Cliente.class);
    Contacto contacto = objectMapper.readValue(datos.get("contacto"), Contacto.class);
    HttpHeaders headers = new HttpHeaders();
    headers.setLocation(ucBuilder.path("/cliente/{id}").buildAndExpand(cliente.getIdCliente()).toUri());
    System.out.println("headers vale " + headers);
    clienteDAO.insertarCliente(cliente);
    Integer ultimoIdCliente = clienteDAO.buscarUltimoIdClienteEnBDporNombreCliente(cliente.getNombre());
    contactoDAO.insertarContactoCliente(contacto, ultimoIdCliente);

    return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}
    
answered by 31.05.2016 в 21:58