Deserialize LocalDate

489
18 апреля 2018, 08:57

Всем привет! Есть Restful вебсервис написанный с Spring Boot, который отдает entity с полем LocalDate с контроллера. И есть клиент для него на Андроиде, но проблема в том, что при попытке получить ответ вылетает ошибка, что не может десериализовать LocalDate. Попробовала решение - написать кастомный Deserializer и прописать соответствующую аннотацию над полем класса, но не сработало. Можно ли вообще эту проблему решить не со стороны сервера, а со стороны клиента?

Код десериализатора:

public class LocalDateDeserializerImpl extends StdDeserializer<LocalDate> {
    public LocalDateDeserializerImpl() {
        super(LocalDate.class);
    }
    @Override
    public LocalDate deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        return LocalDate.parse(parser.readValueAs(String.class));
    }
}

Код контроллера:

@RestController
@AllArgsConstructor
class EmployeeRequestController {
    @GetMapping(value = "/employee-requests/username/{username}")
    List<EmployeeRequestResponse> getDaysWithDecision(
            @PathVariable("username") String username,
            @RequestParam(required = false)
            @DateTimeFormat(iso = DATE) LocalDate date
    ) {
        return employeeRequestService.getDatesWithEmployeeRequestStatuses(username, date);
    }
}

Сама сущность:

@Builder
@Value
public class EmployeeRequestResponse {
    String username;
    @JsonDeserialize(using = LocalDateDeserializerImpl.class)
    LocalDate date;
    RequestStatus requestStatus;
}

Код в клиенте:

private class DaysTask extends AsyncTask<Void, Void, EmployeeRequestResponse[]> {
        @Override
        protected EmployeeRequestResponse[] doInBackground(Void... voids) {
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setAccept(Arrays.asList(new MediaType[]{MediaType.APPLICATION_JSON}));
            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<EmployeeRequestResponse[]>httpEntity = new HttpEntity<>(httpHeaders);
            RestTemplate template = new RestTemplate();
            template.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
            EmployeeRequestResponse[] data2 = template.getForObject(Constants.URL.GET_DATES_FOR_EMPLOYEE, EmployeeRequestResponse[].class);
            return data2;
}

Вот что с сервера приходит

E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
                  Process: appname, PID: 12352
                  java.lang.RuntimeException: An error occurred while executing doInBackground()
                      at android.os.AsyncTask$3.done(AsyncTask.java:353)
                      at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
                      at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
                      at java.util.concurrent.FutureTask.run(FutureTask.java:271)
                      at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
                      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
                      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
                      at java.lang.Thread.run(Thread.java:764)
                   Caused by: org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Cannot construct instance of `appname.EmployeeRequestResponse` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('2018-04-17')
                      at [Source: (com.android.okhttp.okio.RealBufferedSource$1); line: 1, column: 2] (through reference chain: java.lang.Object[][0]); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `appname.EmployeeRequestResponse` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('2018-04-17')
                      at [Source: (com.android.okhttp.okio.RealBufferedSource$1); line: 1, column: 2] (through reference chain: java.lang.Object[][0])
                      at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readInternal(MappingJackson2HttpMessageConverter.java:126)
                      at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:147)
                      at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:76)
                      at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:484)
                      at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:439)
                      at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:237)
                      at appname.MainActivity$DaysTask.doInBackground(MainActivity.java:136)
                      at appname.MainActivity$DaysTask.doInBackground(MainActivity.java:127)
                      at android.os.AsyncTask$2.call(AsyncTask.java:333)
                      at java.util.concurrent.FutureTask.run(FutureTask.java:266)
                      at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245) 
                      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 
                      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 
                      at java.lang.Thread.run(Thread.java:764) 
                   Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `appname.EmployeeRequestResponse` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('2018-04-17')
                      at [Source: (com.android.okhttp.okio.RealBufferedSource$1); line: 1, column: 2] (through reference chain: java.lang.Object[][0])
                      at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1342)
                      at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1031)
                      at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:371)
                      at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:323)
                      at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1366)
                      at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:171)
                      at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:161)
                      at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:195)
                      at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:21)
                      at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
                      at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3072)
                      at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readInternal(MappingJackson2HttpMessageConverter.java:123)
Answer 1

Такое в общем нашла решение, может корявое но работает. Просто напрямую считываю строки с Json-а и конвертирую как мне надо

private class DaysTask extends AsyncTask<Void, Void, LocalDate>{
        @Override
        protected LocalDate doInBackground(Void... voids) {
            LocalDate date = null;
            try {
                URL url = new URL(Constants.URL.GET_DATES_FOR_EMPLOYEE);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");
                InputStream responseBody = connection.getInputStream();
                InputStreamReader responseBodyReader =
                        new InputStreamReader(responseBody, "UTF-8");
                JsonReader jsonReader = new JsonReader(responseBodyReader);
                jsonReader.setLenient(true);
                while (jsonReader.peek().equals(JsonToken.STRING)) {
                    String line = jsonReader.nextString();
                    date = LocalDate.parse(line, DateTimeFormatter.ISO_LOCAL_DATE);
                    break;
                }
                jsonReader.close();
                connection.disconnect();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }catch (IOException e){
                e.printStackTrace();
            }
            return date;
        }

Всем спасибо кто откликнулся и пытался помочь) Доброго всем дня!=)))

READ ALSO
Не могу подключится к SQL SERVER 2012 java

Не могу подключится к SQL SERVER 2012 java

Пытаюсь подключится к удаленной базе данных на сервереВыдает ошибку:

171
Как передать массив в виде аргумента в OpenCL

Как передать массив в виде аргумента в OpenCL

Вопрос: как можно в jocl предать массив в виде аргумента?

146
Как заменить Глиф (Glyph) одного символа на глиф другого символа для шрифтов типа otf

Как заменить Глиф (Glyph) одного символа на глиф другого символа для шрифтов типа otf

Нужно заменить поменять местами глиф символа А и БЧто бы когда вводился символ А выводился символ Б и наоборот

199