Montag, Januar 27, 2020

Frühjahr + Jackson + joda time: so legen Sie die Serialisierung/Deserialisierung-format?

Habe ich die folgende Klasse:

public static class ARestRequestParam
{
    String name;
    LocalDate date;  //joda type
}

Und ich will es deserialisiert werden aus der folgenden JSON, die verarbeitet wird, durch jackson.

{ name:“abc“, Datum:“20131217″ }

Eigentlich will ich zu Deserialisieren alle LocalDate Feld in einer Klasse mit „JJJJMMTT“ – format, ohne duplizieren der format-string ohne jede setter-Methode, ohne XML-Konfiguration. (Das ist, Beschriftungs-und Java-code ist besser)
Wie kann es getan werden?

Auch, ich auch wollen zu wissen die Serialisierung Teil. das ist, LocalDate -> „JJJJMMTT“.

Gesehen hab ich Folgendes:

Aber ich weiß nicht, was anwendbar ist, und die meisten up-to-date.

BTW, ich benutze Spring Boot.

UPDATE

Ok, ich habe es geschafft, zu schreiben funktionierenden code für die Deserialisierung Teil.
Es ist wie folgt:

@Configuration
@EnableWebMvc
public class WebMvcConfiguration extends WebMvcConfigurerAdapter
{
    @Override
    public void configureMessageConverters(
        List<HttpMessageConverter<?>> converters)
    {
        converters.add(jacksonConverter());
    }

    @Bean
    public MappingJackson2HttpMessageConverter jacksonConverter()
    {
        MappingJackson2HttpMessageConverter converter =
            new MappingJackson2HttpMessageConverter();

        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new ApiJodaModule());
        converter.setObjectMapper(mapper);

        return converter;
    }

    @SuppressWarnings("serial")
    private class ApiJodaModule extends SimpleModule
    {
        public ApiJodaModule()
        {
            addDeserializer(LocalDate.class, new ApiLocalDateDeserializer());
        }
    }

    @SuppressWarnings("serial")
    private static class ApiLocalDateDeserializer
        extends StdScalarDeserializer<LocalDate>
    {
        private static DateTimeFormatter formatter =
            DateTimeFormat.forPattern("yyyyMMdd");

        public ApiLocalDateDeserializer() { super(LocalDate.class); }

        @Override
        public LocalDate deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException
        {
            if (jp.getCurrentToken() == JsonToken.VALUE_STRING)
            {
                String s = jp.getText().trim();
                if (s.length() == 0)
                    return null;
                return LocalDate.parse(s, formatter);
            }
            throw ctxt.wrongTokenException(jp, JsonToken.NOT_AVAILABLE,
                "expected JSON Array, String or Number");
        }
    }
}

Ich hatte zur Umsetzung der deserializer mich, da die datetime-format für die deserializer, die im jackson-datatype-joda nicht verändert werden kann. So, da habe ich umgesetzt deserializer mich, jackson-datatype-joda ist nicht erforderlich. (obwohl ich kopiert habe Teile des Codes)

Ist dieser code Ok?

Ist dieser up-to-date-Lösung?

Gibt es einen anderen einfacheren Weg?

Jeder Vorschlag wäre sehr dankbar.

UPDATE

Folgenden Dave Syer Vorschlag, modifizierte ich die Quelle oben wie folgt:

Entfernt 2 Methoden: configureMessageConverters(), jacksonConverter()

Hinzugefügt folgende Methode in WebMvcConfiguration-Klasse:

@Bean
public Module apiJodaModule()
{
    return new ApiJodaModule();
}

Aber jetzt funktioniert es nicht. Es scheint apiJodaModule() wird ignoriert.

Wie kann ich machen, damit es funktioniert?

(Es scheint, dass ich nicht haben sollte eine Klasse, die hat @EnableWebMvc, diese Funktion zu verwenden.)

Die version, die ich benutze, ist org.springframework.boot:spring-boot-starter-web:0.5.0.M6.

UPDATE

Letzte funktionierende version ist wie folgt: (mit anderen Konfigurationen, die ich bisher gemacht haben in der Klasse, die hatte @EnableWebMvc)

Wie Dave Syer erwähnt, funktioniert das nur auf BUILD-SNAPSHOT-version, zumindest für jetzt.

@Configuration
public class WebMvcConfiguration
{
    @Bean
    public WebMvcConfigurerAdapter apiWebMvcConfiguration()
    {
        return new ApiWebMvcConfiguration();
    }

    @Bean
    public UserInterceptor userInterceptor()
    {
        return new UserInterceptor();
    }

    public class ApiWebMvcConfiguration extends WebMvcConfigurerAdapter
    {
        @Override
        public void addInterceptors(InterceptorRegistry registry)
        {
            registry.addInterceptor(userInterceptor())
                .addPathPatterns("/api/user/**");
        }

        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry)
        {
            registry.addResourceHandler("/**")
                .addResourceLocations("/")
                .setCachePeriod(0);
        }
    }

    @Bean
    public Module apiJodaModule()
    {
        return new ApiJodaModule();
    }

    @SuppressWarnings("serial")
    private static class ApiJodaModule extends SimpleModule
    {
        public ApiJodaModule()
        {
            addDeserializer(LocalDate.class, new ApiLocalDateDeserializer());
        }

        private static final class ApiLocalDateDeserializer
            extends StdScalarDeserializer<LocalDate>
        {
            public ApiLocalDateDeserializer() { super(LocalDate.class); }

            @Override
            public LocalDate deserialize(JsonParser jp,
                DeserializationContext ctxt)
                throws IOException, JsonProcessingException
            {
                if (jp.getCurrentToken() == JsonToken.VALUE_STRING)
                {
                    String s = jp.getText().trim();
                    if (s.length() == 0)
                        return null;
                    return LocalDate.parse(s, localDateFormatter);
                }
                throw ctxt.mappingException(LocalDate.class);
            }
        }

        private static DateTimeFormatter localDateFormatter =
            DateTimeFormat.forPattern("yyyyMMdd");
    }
}
InformationsquelleAutor zeodtr | 2013-12-18

1 Kommentar

  1. 5

    Dein code ist OK, aber wenn Sie @EnableWebMvc in eine Spring-Boot-Anwendung, die Sie schalten Sie die Standard-Einstellungen in den Rahmen, so sollten Sie vielleicht vermeiden, dass. Auch Sie haben jetzt nur eine HttpMessageConverter im MVC handler-adapter. Wenn Sie einen snapshot von Spring Boot, Sie sollten in der Lage sein zu definieren einfach eine @Bean Typ Module und alles andere würde automatisch erfolgen, so würde ich empfehlen, es zu tun auf diese Weise.

    • Danke. Eigentlich hatte ich hinzufügen addResourceHandlers (), um WebMvcConfiguration Klasse zu dienen, die statische Dateien(da die Standard-Einstellungen waren Weg). Aber da ich überschrieb addInterceptors() zum hinzufügen von URL-interceptors, die ich hatte, um meine eigene Klasse, die hat EnableWebMvc.
    • Auch, überprüfen Sie bitte mein update und mir einen Vorschlag.
    • Sie brauchen nicht @EnableWebMvc um Abfangjäger, fügen Sie einfach eine @Bean Typ WebMvcConfigurerAdapter (standard-Spring MVC-Funktion). Die Antwort Lesen: „verwenden Sie einen snapshot“. Das sollte Sortieren Sie aus.
    • Danke. Ich habe gerade realisiert, die es können mehrere WebMvcConfigurerAdapters, durch das Lesen der Frühlings-source-code. BTW, ich weiß nicht, was genau „bedeutet“ einen snapshot“. Wie kann ich geben Sie es in eine zu bauen.gradle-Datei? (Meine Kenntnisse der Java-Entwicklungsumgebung ist zu klein), Da HttpMessageConvertersAutoConfiguration.java geändert wurde nur 2 Tage her, vielleicht ist das feature nicht enthalten in M6. Also, sollte ich laden Sie die spring-boot von github?
    • Nein, es ist nicht enthalten in M6, das ist, warum Sie benötigen, um eine Momentaufnahme. Wenn Sie das richtige repository-Konfiguration (beachten Sie die website), dann ändern Sie einfach die version label von „M6“ zu „BUILD-SNAPSHOT“.
    • Ich danke Ihnen sehr. Ich werde versuchen, dass. Sorry für solche Fragen, eine grundlegende Frage. BTW, nur heute habe ich gemerkt, dass das ‚M‘ in ‚M6‘ bedeutet ‚Meilenstein’…
    • Es funktioniert. Ich habe aktualisiert die Frage, um die endgültige version arbeiten.
    • Gibt es eine Möglichkeit, ändern Sie die ‚Vanille‘ ObjectMapper? Wie doc erwähnte „Wenn Jackson auf den classpath bekommt man bereits eine Standard-Konverter mit einer Vanille-ObjectMapper.“ Wie ich bekannt, wenn wir objectMapper.konfigurieren(SerializationConfig.Funktion.WRITE_DATES_AS_TIMESTAMPS, false); bekommen, was wir wollen.
    • Erstellen Sie eine @Bean Typ ObjectMapper

Kostenlose Online-Tests