14

I'm trying to send a list of files with Spring Rest but I get this exception.

Could not write content: No serializer found for class java.io.ByteArrayInputStream

It works with one file (ByteArrayResource).

It does not work with a list of files (List<ByteArrayResource>).

Here is the important parts of my code:

List<ByteArrayResource> contentsAsResource = new ArrayList<ByteArrayResource>();
for(MultipartFile fichier : fichiers) {
    contentsAsResource.add(new ByteArrayResource(fichier.getBytes()) {
        @Override
        public String getFilename()
        {
            return fichier.getOriginalFilename();
        }
    });
};
map.add("files", contentsAsResource);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<LinkedMultiValueMap<String, Object>>(map, headers);

FormHttpMessageConverter formConverter = new FormHttpMessageConverter();
formConverter.setMultipartCharset(Charset.forName("UTF8"));
formConverter.addPartConverter(new MappingJackson2HttpMessageConverter());

this.restClientHelper.getRestTemplate().getMessageConverters().add(formConverter);
this.restClientHelper.getRestTemplate().postForObject("file/save", requestEntity, Object.class);

I've tried the following which did not work :

  • send an array instead of a list
  • wrap the list in a dto
  • send bytes[] but it does not work when the file > 1.5Mb

I've been debugging the deserialization but it's such a pain to understand!

If it can help, With one file, the converter 'ResourceHttpMessageConverter' is used.

Anyone have an idea?

EDIT: The request works if I add each file by file in the map (instead of a list).

for (MultipartFile fichier : fichiers) {
  map.add("files", new ByteArrayResource(fichier.getBytes()) {
    @Override
    public String getFilename()
    {
      return fichier.getOriginalFilename();
    }
  });
};

but I get another exception : org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:8080/myApp/ws/file/save". There is a basic authentication enabled on the destination server. If i disabled it, everything is working! Here is the spring-security configuration on the destination server.

<http pattern="/ws/file/**" authentication-manager-ref="basicAuthenticationManager" create-session="stateless">
        <intercept-url pattern="/**" access="isAuthenticated()"/>
        <http-basic />

        <csrf disabled="true" />
        <headers disabled="true" />
</http>

Am I missing something in the spring security configuration ?

EDIT 2 : it seems there is not the token "Authorization" in the headers, adding it manually fix the problem

EDIT 3 : Problem solved! When sending multiples files with spring rest template to a destination server with basic auth enabled, it's needed to (re)add the basic authent token. It's well explained here : Basic authentication for REST API using spring restTemplate. I don't know if it's a bug or not (from Spring). My configuration before this update (I chose interceptor way) was this :

final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(login, motDePasse));
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
...
final HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClientBuilder.build());
this.restTemplate = new RestTemplate(requestFactory);

I've added this :

this.restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor(username, password));

The class is :

 private static class BasicAuthorizationInterceptor implements ClientHttpRequestInterceptor
 {

   private final String username;

   private final String password;

   public BasicAuthorizationInterceptor(String username, String password)
   {
    this.username = username;
    this.password = (password == null ? "" : password);
   }

   @Override
   public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException
   {
    byte[] token = Base64.getEncoder().encode((this.username + ":" + this.password).getBytes());
    request.getHeaders().add("Authorization", "Basic " + new String(token));
    return execution.execute(request, body);
   }

  }
Community
  • 1
  • 1
Clemzd
  • 895
  • 2
  • 15
  • 35
  • [Refer this ](http://stackoverflow.com/questions/25103070/resttemplate-httpmessagenotwritableexception-no-serializer-found-for-class-ja) – Onkar Nov 25 '16 at 14:41
  • Thanks. I've seen this post. My code is quite the same. – Clemzd Nov 28 '16 at 10:05
  • so your question is no longer about Spring Rest Template but about spring security? If you want to support security on the destination server your request should be authenticated (setting header ex: `Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l` – Nikolay Rusev Nov 28 '16 at 10:47
  • Indeed! The headears are correctly set with any other services. May be it's not with this file upload because I manually create Headers to say it's a multipart requests. I'm searching around this. – Clemzd Nov 28 '16 at 10:54
  • @Clemzd if you found an answer you can always answer your question. And plz do so – Eugene Dec 04 '16 at 13:07
  • Had issue with jersey which jersey where passing list caused issue then used below json dependency and it got resolved seems there was issue with converting List,Array to JSON org.glassfish.jersey.media jersey-media-json-jackson 2.24.1 – gladiator Dec 05 '16 at 09:04

1 Answers1

1

in the spring security configuration file is missing authentication provider . you can try this instead interceptor

<authentication-manager>
   <authentication-provider>
       <user-service>
       <user name="user" password="password"  />
       </user-service>
   </authentication-provider>
</authentication-manager>