xhr how data create json spring rest curl jackson

how - Publicar JSON en la API REST



send object post javascript (9)

Aquí hay una solución de prueba unitaria similar a la respuesta de yoram givon: https://stackoverflow.com/a/22516235/1019307 .

public class JSONFormatTest { MockMvc mockMvc; // The controller used doesn''t seem to be important though YMMV @InjectMocks ActivityController controller; @Before public void setup() { MockitoAnnotations.initMocks(this); this.mockMvc = standaloneSetup(controller).setMessageConverters(new MappingJackson2HttpMessageConverter()) .build(); } @Test public void thatSaveNewDataCollectionUsesHttpCreated() throws Exception { String jsonContent = getHereJSON02(); this.mockMvc .perform( post("/data_collections").content(jsonContent).contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isCreated()); } private String getHereJSON01() { return "{/"dataCollectionId/":0,/"name/":/"Sat_016/",/"type/":/"httpUploadedFiles/"," ... } }

Ejecute la prueba de la unidad y la print() debe imprimir el MockHttpServletRequest incluyendo la Excepción.

En Eclipse (no estoy seguro de cómo hacerlo en otros IDE), haga clic en el enlace Excepción y se abrirá un cuadro de diálogo de propiedades para esa excepción. Marque la casilla ''Habilitado'' para interrumpir esa excepción.

Depure la prueba de unidad y Eclipse se interrumpirá en la excepción. Inspeccionarlo debería revelar el problema. En mi caso fue porque tenía dos de la misma entidad en mi JSON.

Estoy creando una API REST que aceptará solicitudes JSON.

Lo estoy probando usando CURL:

curl -i -POST -H ''Accept: application/json'' -d ''{"id":1,"pan":11111}'' http://localhost:8080/PurchaseAPIServer/api/purchase


Pero obteniendo el siguiente error:

HTTP/1.1 415 Unsupported Media Type Server: Apache-Coyote/1.1 Content-Type: text/html;charset=utf-8 Content-Length: 1051 Date: Wed, 25 Apr 2012 21:36:14 GMT The server refused this request because the request entity is in a format not supported by the requested resource for the requested method ().



Cuando la depuración nunca llega a mi acción de crear en el controlador.

import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; 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; import org.springframework.web.bind.annotation.ResponseStatus; import com.app.model.Purchase; import com.app.service.IPurchaseService; @Controller public class PurchaseController { @Autowired private IPurchaseService purchaseService; @RequestMapping(value = "purchase", method = RequestMethod.GET) @ResponseBody public final List<Purchase> getAll() { return purchaseService.getAll(); } @RequestMapping(value = "purchase", method = RequestMethod.POST) @ResponseStatus( HttpStatus.CREATED ) public void create(@RequestBody final Purchase entity) { purchaseService.addPurchase(entity); } }



ACTUALIZAR

Agregué la configuración de Jackson a AppConfig.java:

@Configuration @ComponentScan(basePackages = "com.app") public class AppConfig { @Bean public AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter() { final AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter = new AnnotationMethodHandlerAdapter(); final MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJacksonHttpMessageConverter(); HttpMessageConverter<?>[] httpMessageConverter = { mappingJacksonHttpMessageConverter }; String[] supportedHttpMethods = { "POST", "GET", "HEAD" }; annotationMethodHandlerAdapter.setMessageConverters(httpMessageConverter); annotationMethodHandlerAdapter.setSupportedMethods(supportedHttpMethods); return annotationMethodHandlerAdapter; } }



Mis GET están funcionando correctamente ahora:

curl -i -H "Content-Type:application/json" -H "Accept:application/json" http://localhost:8080/PurchaseAPIServer/api/purchase HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: application/json Transfer-Encoding: chunked Date: Thu, 26 Apr 2012 21:19:55 GMT [{"id":1,"pan":111}]



Pero obtengo lo siguiente cuando intento un POST:

curl -i -X POST -H "Content-Type:application/json" -H "Accept:application/json" http://localhost:8080/PurchaseAPIServer/api/purchaseMe -d "{"id":2,"pan":122}" HTTP/1.1 400 Bad Request Server: Apache-Coyote/1.1 Content-Type: text/html;charset=utf-8 Content-Length: 971 Date: Thu, 26 Apr 2012 21:29:56 GMT Connection: close The request sent by the client was syntactically incorrect ().



Mi modelo:

@Entity @XmlRootElement public class Purchase implements Serializable { /** * */ private static final long serialVersionUID = 6603477834338392140L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private Long pan; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public Long getPan() { return pan; } public void setPan(Long pan) { this.pan = pan; } }



¿Alguna idea de dónde voy mal?

Gracias


Como sugirió sdouglass , Spring MVC detecta automáticamente a Jackson y configura un MappingJacksonHttpMessageConverter para manejar la conversión a / desde JSON. Pero sí necesitaba explícitamente configurar el convertidor para que funcione, como también lo señaló.

Agregué lo siguiente y mis solicitudes de CURL GET estaban funcionando ... Hola.

AppConfig.java

@Configuration @ComponentScan(basePackages = "com.app") public class AppConfig { @Bean public AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter() { final AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter = new AnnotationMethodHandlerAdapter(); final MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJacksonHttpMessageConverter(); HttpMessageConverter<?>[] httpMessageConverter = { mappingJacksonHttpMessageConverter }; String[] supportedHttpMethods = { "POST", "GET", "HEAD" }; annotationMethodHandlerAdapter.setMessageConverters(httpMessageConverter); annotationMethodHandlerAdapter.setSupportedMethods(supportedHttpMethods); return annotationMethodHandlerAdapter; } }


curl -i -H "Content-Type:application/json" -H "Accept:application/json" http://localhost:8080/PurchaseAPIServer/api/purchase HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: application/json Transfer-Encoding: chunked Date: Thu, 26 Apr 2012 21:19:55 GMT [{"id":1,"pan":111}]



Pero el siguiente CURL POST aún no funcionaba (nunca presionó la acción del controlador y no dio información de depuración de la consola).

curl -i -X POST -H "Content-Type:application/json" http://localhost:8080/PurchaseAPIServer/api/purchaseMe -d "{"id":2,"pan":122}" HTTP/1.1 400 Bad Request Server: Apache-Coyote/1.1 Content-Type: text/html;charset=utf-8 Content-Length: 971 Date: Thu, 26 Apr 2012 21:29:56 GMT Connection: close The request sent by the client was syntactically incorrect ().



Así que agregué Logback para iniciar un proceso detallado de depuración.

<configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n </pattern> </encoder> </appender> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>/home/thomas/springApps/purchaseapi.log</file> <encoder> <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n </pattern> </encoder> </appender> <logger name="org.hibernate" level="DEBUG" /> <logger name="org.springframework" level="TRACE" /> <logger name="org.springframework.transaction" level="INFO" /> <logger name="org.springframework.security" level="INFO" /> <!-- to debug security related issues (DEBUG) --> <logger name="org.springframework.web.servlet.mvc" level="TRACE" /> <!-- some serialization issues are at trace level here: org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod --> <!-- our service --> <logger name="com.app" level="DEBUG" /> <!-- <logger name="com.app" level="INFO" /> --><!-- to follow if setup is being executed --> <root level="INFO"> <appender-ref ref="FILE" /> </root> </configuration>



Agregar la depuración de nivel TRACE a org.springframework.web.servlet.mvc me dio la respuesta al problema.

2012-04-28 14:17:44,579 DEBUG [http-bio-8080-exec-3] o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor [AbstractMessageConverterMethodArgumentResolver.java:117] Reading [com.app.model.Purchase] as "application/json" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter@74a14fed] 2012-04-28 14:17:44,604 TRACE [http-bio-8080-exec-3] o.s.w.s.m.m.a.ServletInvocableHandlerMethod [InvocableHandlerMethod.java:159] Error resolving argument [0] [type=com.app.model.Purchase] HandlerMethod details: Controller [com.app.controller.PurchaseController] Method [public void com.app.controller.PurchaseController.create(com.app.model.Purchase)] org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Unexpected character (''p'' (code 112)): was expecting double-quote to start field name



Cambié mis CURL POSTs a la siguiente y todo funcionó:

curl -i -X POST -H "Content-Type:application/json" http://localhost:8080/PurchaseAPIServer/api/purchase -d ''{"pan":11111}'' HTTP/1.1 201 Created Server: Apache-Coyote/1.1 Content-Length: 0 Date: Sat, 28 Apr 2012 13:19:40 GMT

Esperemos que alguien encuentre esto útil.


Es 2014 y quería agregar algunas actualizaciones a esta pregunta que me ayudaron a resolver el mismo problema.

  1. Actualización de código para reemplazar AnnotationMethodHandlerAdapter en desuso en Spring 3.2

    @Configuration public class AppConfig {

    @Bean public RequestMappingHandlerAdapter annotationMethodHandlerAdapter() { final RequestMappingHandlerAdapter annotationMethodHandlerAdapter = new RequestMappingHandlerAdapter(); final MappingJackson2HttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJackson2HttpMessageConverter(); List<HttpMessageConverter<?>> httpMessageConverter = new ArrayList<HttpMessageConverter<?>>(); httpMessageConverter.add(mappingJacksonHttpMessageConverter); String[] supportedHttpMethods = { "POST", "GET", "HEAD" }; annotationMethodHandlerAdapter.setMessageConverters(httpMessageConverter); annotationMethodHandlerAdapter.setSupportedMethods(supportedHttpMethods); return annotationMethodHandlerAdapter; } }

  2. HTTP / 1.1 415 Error de tipo de soporte no compatible

Después de pasar muchas horas tratando de averiguar por qué AÚN ASÍ ESTÉ ENTENDIENDO un error 415, incluso después de agregar la configuración JSON correcta, finalmente me di cuenta de que el problema NO estaba en el lado del servidor sino en el lado del cliente. Para que Spring acepte su JSON, DEBE asegurarse de enviar tanto "Content-Type: application / json" como "Accept: application / json" como parte de sus encabezados http. específicamente para mí fue una aplicación de Android HttpUrlConnection que tuve que configurar como:

public static String doPost(final String urlString,final String requestBodyString) throws IOException { final URL url = new URL(urlString); final HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); try { urlConnection.setReadTimeout(10000 /* milliseconds */); urlConnection.setConnectTimeout(15000 /* milliseconds */); urlConnection.setRequestProperty("Content-Type", "application/json"); urlConnection.setRequestProperty("Accept", "application/json"); urlConnection.setDoOutput(true); urlConnection.setRequestMethod("POST"); urlConnection.setChunkedStreamingMode(0); urlConnection.connect(); final PrintWriter out = new PrintWriter(urlConnection.getOutputStream()); out.print(requestBodyString); out.close(); final InputStream in = new BufferedInputStream(urlConnection.getInputStream()); final String response = readIt(in); in.close(); //important to close the stream return response; } finally { urlConnection.disconnect(); } }


Experimenté una vez y finalmente lo resolví agregando el archivo jar jackson-mapper-asl.jar. Verifique si ha incluido todas estas dependencias, aunque la excepción en sí misma no le dice eso.

Y realmente no necesita configurar explícitamente el bean, y no necesita poner "consumes" en la declaración de @RequestMapping. Estoy usando la primavera 3.1 por cierto.

contentType: "application / json" es el único que necesita configurar. Sí, del lado del cliente.


Intenta agregar el siguiente código en la configuración de tu aplicación

<mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper" ref="jacksonObjectMapper" /> </bean> </mvc:message-converters>


Intente agregar un descriptor de lo que está en su solicitud POST. Es decir, agregue para curl el encabezado:

Content-Type: application/json

Si no lo agrega, curl usará el text/html predeterminado independientemente de lo que envíe.

Además, en PurchaseController.create() debe agregar que el tipo aceptado es application/json .


Si recuerdo correctamente, los documentos de Spring dicen que Spring MVC detectará automáticamente a Jackson en la ruta de clase y configurará un MappingJacksonHttpMessageConverter para manejar la conversión a / desde JSON, pero creo que he experimentado situaciones en las que tuve que configurar manualmente / explícitamente ese convertidor para obtener Cosas para trabajar. Puede intentar agregar esto a su configuración MVC XML:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"> </list> </property> </bean>

ACTUALIZACIÓN : Fue este más el formato correcto del JSON que se está publicando, consulte https://.com/a/10363876/433789


Tuve el mismo problema y lo resolví.

1 agregue MappingJackson2HttpMessageConverter como se describe en ese hilo (vea también la sección 4 http://www.baeldung.com/spring-httpmessageconverter-rest )

2 usa el comando correcto (con símbolos de escape):

curl -i -X POST -H "Content-Type:application/json" -d "{/"id/":/"id1/",/"password/":/"password1/"}" http://localhost:8080/user


Tuve el mismo problema, que se resolvió con dos cambios en mi código:

  1. Falta @PathVariable en mi argumento de método, mi método no tenía ningún
  2. El siguiente método en mi clase SpringConfig, desde el que tenía con el interceptor del manejador, está en desuso y da algunos problemas:

    public RequestMappingHandlerAdapter RequestMappingHandlerAdapter() { final RequestMappingHandlerAdapter requestMappingHandlerAdapter = new RequestMappingHandlerAdapter(); final MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJacksonHttpMessageConverter(); final String[] supportedHttpMethods = { "POST", "GET", "HEAD" }; requestMappingHandlerAdapter.getMessageConverters().add(0, mappingJacksonHttpMessageConverter); requestMappingHandlerAdapter.setSupportedMethods(supportedHttpMethods); return requestMappingHandlerAdapter; }