简体   繁体   中英

406 HttpMediaTypeNotAcceptableException: Could not find acceptable representation for “text/calendar” type output

I'm trying to serve an ICS file with Spring Boot. I can not manage to repond with the right Content-Type (i'm in Junit). I think a build a correct reponse but Spring override it.

In my @RestController I have this

@GetMapping(value="/meeting/ics/{id}",produces = "text/calendar;charset=UTF-8")
public ResponseEntity<byte[]> getMeetingRoomCalendar(@PathVariable("id") Long id) throws ParseException, URISyntaxException, IOException {
    //...

    byte[]out= calendar.toString().getBytes();

    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.setContentType(new MediaType("text", "calendar", Charset.forName("UTF-8")));
    responseHeaders.setContentLength(out.length);

    return new ResponseEntity<>(out,responseHeaders,HttpStatus.OK);
}

and I test it this way :

MvcResult mvcResult = restMembershipConfigMockMvc.perform(get("/api/meeting/ics/1")
        .accept(MediaType.ALL))
        .andExpect(status().isOk())
        .andReturn()
        ;

I tried several reponses found on similar question here in Stack overflow but I always receive a 406 status with this exception thrown HttpMediaTypeNotAcceptableException: Could not find acceptable representation response

Here I removed the ".ics" from the path suffix to exclude this to cause the exception.

Ok, I found the way. There were too many wrong points in my question. The reason why it didn't work was because Spring mvc doesn't provide an HttpMessageConverter that support the type "text/calendar".

So I created one (i use ical4j library so i want my controller to respond that kind of object):

public class ICSHttpMessageConverter<T> extends AbstractHttpMessageConverter<T>
{

    public ICSHttpMessageConverter() {
        super(new MediaType("text","calendar"));
    }

    @Override
    protected boolean supports(Class<?> aClass) {
        return true;
    }


    @Override
    protected T readInternal(Class<? extends T> aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
        CalendarBuilder calendarBuilder = new CalendarBuilder();
        Calendar calendar = null;
        try {
             calendar = calendarBuilder.build(httpInputMessage.getBody());

        } catch (ParserException e) {
            e.printStackTrace();
        }
        return (T)calendar;
    }

    @Override
    protected void writeInternal(T t, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {
        httpOutputMessage.getBody().write(t.toString().getBytes());
    }
}

I probably should improve the support method but at that point everything works and i'm happy to go away to other missions.

Now we just have register the converter in Spring configuration :

@Configuration
public class MediaTypeConfiguration extends WebMvcConfigurationSupport {

    @Override
    protected void configureMessageConverters(List<HttpMessageConverter<?>> converters){
        converters.add(new ICSHttpMessageConverter());
        super.addDefaultHttpMessageConverters(converters);
    }
}

After that my controller looks like this :

@GetMapping(value="/meeting/ics/{id}.ics")
public ResponseEntity<Calendar> getMeetingRoomCalendar(@PathVariable("id") Long id) throws ParseException, URISyntaxException, IOException {
    //...
    calendar = ICSMeetingRoomAgendaHandler.loadBookings(calendar,bookingDTOS,meetingRoomDTO);

    return ResponseEntity.ok().body(calendar);
}

At that point my only problem is that in my junit integration test my converter didn't look to be registred. It was because my MockMvc was not given the converter at the mock init. I just had to add it in with the method setMessageConverters

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM