2

I am a new for Spring, using Spring 4.2.0. I want to return a JSON to client. It always return 406 error to client.

Here is my code,

@RequestMapping(
    value = "/account",
    method = RequestMethod.GET,
    headers="Accept=*/*"
)
@ResponseBody
public Object account() throws ClientProtocolException, IOException{
    JSONArray result = null;
    HttpGet request = new HttpGet(baseURL+"/user/accountuser/2");
    request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
    request.setHeader(HttpHeaders.AUTHORIZATION, authenCode);
    HttpResponse response = client.execute(request);
    String json = IOUtils.toString(response.getEntity().getContent());
    try {
        result = new JSONArray(json); // here is a json array from 3rd services
        System.out.println(result);
        return result;
    } catch (JSONException e) {
        e.printStackTrace();
    }
    return null;
}

I tried solution from this question Spring MVC Controller Return JSON - Error 406 by using

    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-core-asl</artifactId>
        <version>1.9.13</version>
    </dependency>
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.9.13</version>
    </dependency>

It's still same.

After that I tried this solution spring mvc not returning json content - error 406 by using

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.2.3</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.2.3</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.2.3</version>
    </dependency>

instead of before solution, but it's still same.

Moreover, I changed a lot of thing in the @RequestMapping such as

@RequestMapping(value = "/account",method = RequestMethod.GET,headers="Accept=*/*")
@RequestMapping(value = "/account",method = RequestMethod.GET,headers="Accept=application/json")
@RequestMapping(value = "/account",method = RequestMethod.GET,produces = MediaType.APPLICATION_JSON_VALUE)

it's still same too.

I've faced on this problem for 2 day. I don't know how to solve it.

Thanks for help.

Community
  • 1
  • 1
Hikaru Shindo
  • 2,611
  • 8
  • 34
  • 59
  • Could you set log level `DEBUG` on package `org.springframework.web` and post the output? – ksokol Nov 10 '15 at 09:11
  • @ksokol I don't know the right way to set log level to DEBUG, but this output shown in the console, WARN : org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver - Handler execution resulted in exception: Could not find acceptable representation – Hikaru Shindo Nov 10 '15 at 09:59
  • Ok. Two more questions:-) What logging framework do you use? Do you use Spring in a servlet container like Tomcat or do you use Spring Boot? – ksokol Nov 10 '15 at 10:04
  • @ksokol I'm using Tomcat. – Hikaru Shindo Nov 10 '15 at 10:14
  • 1
    Ok. It will take some hours to provide an example. – ksokol Nov 10 '15 at 10:19

2 Answers2

1

My solution is based on Spring's RestTemplate. It is a convenient approach to talk to remote services. Various HttpMessageConverter transform request/response objects into common formats like XML or JSON out of the box as long as the necessary library is available on classpath.

Your code even doesn't require Jackson because it acts as a proxy for a third party service. Please keep in mind. This is a demo and not meant to be used in a production system as is.

@Controller
public class DemoController {

    private final RestTemplate restTemplate = new RestTemplate();
    private final String baseUrl = "http://localhost:8080";

    @RequestMapping(value = "/account", method = GET, produces = APPLICATION_JSON_VALUE)
    public void account(HttpServletResponse response) throws Exception {
        ResponseEntity<Resource> exchange = restTemplate.exchange(baseUrl + "/user/accountuser/2", HttpMethod.GET, createEntity(), Resource.class);
        IOUtils.copy(exchange.getBody().getInputStream(), response.getOutputStream());
    }

    private HttpEntity<String> createEntity() {
        final HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add(AUTHORIZATION, "someCode");
        httpHeaders.setContentType(APPLICATION_JSON);
        return new HttpEntity<String>(httpHeaders);
    }
}
ksokol
  • 8,035
  • 3
  • 43
  • 56
0

There could be two things that are causing this exception, the missing dependencies, or a return value that is not a proper java bean. You can read more here

If you remove the codehaus dependencies and leave only fasterxml you can be certain that you have proper jackson dependencies to feed the converter.

Your problem is however that JSONArray is not a proper java bean. To get it working you can simplify your method to

@RequestMapping(
    value = "/account",
    method = RequestMethod.GET,
    produces=MediaType.APPLICATION_JSON_VALUE
)
@ResponseBody
public String account() throws ClientProtocolException, IOException{
    HttpGet request = new HttpGet(baseURL+"/user/accountuser/2");
    request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
    request.setHeader(HttpHeaders.AUTHORIZATION, authenCode);
    HttpResponse response = client.execute(request);
    String json = IOUtils.toString(response.getEntity().getContent());
    return json;
}

and register application/json type, either in xml

<mvc:annotation-driven >
<mvc:message-converters register-defaults="true">
    <bean class = "org.springframework.http.converter.StringHttpMessageConverter">
               <property name="supportedMediaTypes">
                <list>
                   <value>text/plain;charset=UTF-8</value>
                   <value>text/html;charset=UTF-8</value>
                   <value>application/json;charset=UTF-8</value>
                </list>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven >

or in java config

@Override
public void configureMessageConverters(
        List<HttpMessageConverter<?>> converters) {
    StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(
            Charset.forName("UTF-8"));
    stringConverter.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN, MediaType.TEXT_HTML, 
            MediaType.APPLICATION_JSON));
    converters.add(stringConverter);
}

The fact that you're posting a new get request inside a controller looks very suspicious, but I won't go into that.

What happens when you apply this solution is that, you say that your method will produce a response with json content-type. And since the method is returning String, your adding a config so that StringHttpMessageConverter can apply for json type as well

Community
  • 1
  • 1
Master Slave
  • 27,771
  • 4
  • 57
  • 55