首页 > 解决方案 > 从属性文件将外部日期格式模式设置为 @JsonFormat

问题描述

我们正在尝试使用 @JSONFormat 将 bean 中的日期格式外部化,以便使其可配置。

@JsonFormat(pattern = "${application.date.format}")
private Date creationtime;

或者

@JsonFormat(pattern = "yyyy-MM-DD")
private Date creationtime;

当我给出标准字符串值时,它会起作用。但是,当我们将第一个值中显示的值外部化时,我收到一个异常消息:

java.lang.IllegalArgumentException: Illegal pattern character 'p'

要将变量值分配给第二种方法,我们需要一个作为常量表达式的最终字符串。如何使模式可配置?

标签: javaspringjackson

解决方案


Jackson使用JacksonAnnotationIntrospector处理标准注释。我们可以扩展这个机制,提供我们额外的自省器和默认值。为此,我们可以使用pair方法。

简单的自定义实现可能如下所示:

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.introspect.Annotated;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;

import java.util.Objects;

public class SpringJacksonAnnotationIntrospector extends AnnotationIntrospector {

    private final ApplicationContext context;

    @Autowired
    public SpringJacksonAnnotationIntrospector(ApplicationContext context) {
        this.context = Objects.requireNonNull(context);
    }

    @Override
    public JsonFormat.Value findFormat(Annotated memberOrClass) {
        JsonFormat annotation = _findAnnotation(memberOrClass, JsonFormat.class);
        if (annotation == null) {
            return null;
        }
        String basePattern = annotation.pattern();
        if (basePattern.startsWith("$")) {
            String pattern = context.getEnvironment().getProperty(basePattern.substring(2, basePattern.length() - 1));
            return JsonFormat.Value.forPattern(pattern);
        }
        return null;
    }

    @Override
    public Version version() {
        return new Version(1, 0, 0, "", "org.company", "spring-jackson");
    }
}

上面的实现重用JsonFormat了注解,但我们可以引入新的注解以避免混淆。我们需要注册我们的自定义内省器。有许多不同的方法可以做到这一点,这取决于您的Spring配置。例如,我们可以这样做,如下所示:

import com.example.jackson.SpringJacksonAnnotationIntrospector;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@EnableWebMvc
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private ApplicationContext context;

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        //JSON
        AnnotationIntrospector pairedIntrospectors = AnnotationIntrospector.pair(springJacksonAnnotationIntrospector(),
                new JacksonAnnotationIntrospector());
        converters.add(new MappingJackson2HttpMessageConverter(
                Jackson2ObjectMapperBuilder.json()
                        .annotationIntrospector(pairedIntrospectors)
                        .build()));
    }

    @Bean
    public SpringJacksonAnnotationIntrospector springJacksonAnnotationIntrospector() {
        return new SpringJacksonAnnotationIntrospector(context);
    }
}

从现在开始,Spring应该使用 的全局配置来覆盖日期格式。

也可以看看:


推荐阅读