jackson在springboot中如何实现自定义参数转换器
小编给大家分享一下jackson在springboot中如何实现自定义参数转换器,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!
springboot jackson使用-自定义参数转换器
springboot中默认使用jackson,且实现了很多参数转换器,其中就有EnumToStringConverter和StringToEnumConverterFactory,用于字符串和枚举的互转。但是是根据枚举名称互转。
要实现的功能
空属性我不希望转成json字符串
日期对象我希望按照指定格式转换
我存在多个枚举,类似public enum ChannelWayEnum { Bluetooth(0, "蓝牙"), NB(1, "NB-IOT"), G4(2, "自建4G"), Ali(3, "ali-4G");},用默认转换器无法转换。需要自定义转换。
思路
覆盖默认注入的ObjectMapper,自己实现objectMapper,可设置忽略null字段
自定义针对日期对象的Converter
枚举需要实现接口IEnum,然后自定义针对IEnum接口的转换器
关键代码
注入ObjectMapper
@Configurationpublic class JacksonConfig { @Bean public ObjectMapper objectMapper() { return createObjectMapper(); } private ObjectMapper createObjectMapper(){ ObjectMapper objectMapper = new ObjectMapper(); SimpleModule simpleModule = new SimpleModule(); /** * 序列化:对象=>jsonString */ simpleModule.addSerializer(WashEnum.class, new WashEnumSerializer()); simpleModule.addSerializer(IEnum.class, new EnumSerializer()); simpleModule.addSerializer(Date.class, new DateSerializer()); simpleModule.addSerializer(Boolean.class, new BooleanSerializer()); //忽略null字段 objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); /** * 反序列化:jsonString=>对象 */ //允许json属性名不使用双引号 objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); //忽略不存在字段 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); simpleModule.addDeserializer(String.class, new StringDeserializer()); simpleModule.addDeserializer(Date.class, new DateDeserializer()); simpleModule.addDeserializer(WashEnum.class, new WashEnumDeserializer()); simpleModule.addDeserializer(Enum.class, new EnumDeserializer());//反序列化枚举, simpleModule.addDeserializer(Boolean.class, new BooleanDeserializer()); objectMapper.registerModule(simpleModule); return objectMapper; }}
日期对象的转换
@JsonComponentpublic class DateDeserializer extends JsonDeserializerimplements Converter { @Override public Date deserialize(JsonParser p, DeserializationContext ctxt) { try { return convert(p.getText()); } catch (IOException e) { e.printStackTrace(); } return null; } @Override public Date convert(String source) { if (StringUtil.isBlank(source)) { return null; } return TimeUtil.toDate(TimeUtil.str2Time(source, TimeFormat.DEFAULT)); }}@JsonComponentpublic class DateSerializer extends JsonSerializer implements Converter { @Override public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers){ try { gen.writeString(convert(value)); } catch (IOException e) { e.printStackTrace(); } } @Override public String convert(Date source) { return TimeUtil.time2Str(TimeUtil.date2Time(source),TimeFormat.DEFAULT); }}
接口
/** * 枚举都要继承此接口, * @param枚举实际值的数据类型 */public interface IEnum { //枚举实际值 V getValue(); static T getBean(String value,Class tClass){ if (StringUtil.isBlank(value)){ return null; } for (T enumObj : tClass.getEnumConstants()) { if (value.equals(enumObj.getValue().toString())) { return enumObj; } } return null; } default String getStr(){ return String.valueOf(getValue()); }}
枚举的转换器
/** * json=>对象 */@JsonComponentpublic class EnumDeserializerextends JsonDeserializer implements ContextualDeserializer{ private Class targetClass = null; public EnumDeserializer() { } public EnumDeserializer(Class targetClass) { this.targetClass = targetClass; } @Override public T deserialize(JsonParser p, DeserializationContext ctxt) {// if(targetClass!=null&&IEnum.class.isAssignableFrom(targetClass)){ try { return IEnum.getBean(p.getText(),targetClass); } catch (IOException e) { e.printStackTrace(); }// } return null; } @Override public JsonDeserializer> createContextual(DeserializationContext ctxt, BeanProperty property) { Class targetClass = (Class ) ctxt.getContextualType().getRawClass(); return new EnumDeserializer(targetClass); }}/** * 序列化,将enum枚举转为json * @author chenzy * @since 2019.12.19 */@JsonComponentpublic class EnumSerializer extends JsonSerializer { @Override public void serialize(T value, JsonGenerator gen, SerializerProvider serializers) throws IOException { Optional data = Optional.of(value); if (data.isPresent()) {//非空 gen.writeObject(data.get().getValue()); } else {// gen.writeString(""); } }}
下面才是真正的转换器
/** * IEnum=>str */@Componentpublic class Enum2StrConverter> implements ConditionalConverter,Converter { private final ConversionService conversionService; protected Enum2StrConverter(ConversionService conversionService) { this.conversionService = conversionService; } @Override public String convert(T source) { return source.getStr(); } @Override public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { for (Class> interfaceType : ClassUtils.getAllInterfacesForClassAsSet(sourceType.getType())) { if (this.conversionService.canConvert(TypeDescriptor.valueOf(interfaceType), targetType)) { return false; } } return true; }}/** * str=>IEnum */@Componentpublic class Str2EnumConverte implements ConverterFactory { @Override public Converter getConverter(Class targetType) { return new Str2Enum(targetType); } private static class Str2Enum implements Converter { private final Class enumType; public Str2Enum(Class enumType) { this.enumType = enumType; } @Override public T convert(String source) { if (StringUtil.isBlank(source)) { return null; } return IEnum.getBean(source,enumType); } }}/** * @author chenzy * @since 2020-12-02 */@Configurationpublic class JacksonConfig implements WebMvcConfigurer { @Autowired private Str2EnumConverte str2EnumConverte; @Override public void addFormatters(FormatterRegistry registry) { registry.addConverterFactory(str2EnumConverte); } @Bean public ObjectMapper objectMapper() { return JsonUtil.getObjectMapper(); }}
Jackson自定义转换器
使用jackson进行json和java bean转换时,可以使用注解自定义转换器进行转换。
@JsonDeserialize注解源码
方法注释中写了,using 方法是作用在method上的。
package com.fasterxml.jackson.databind.annotation; import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target; import com.fasterxml.jackson.databind.JsonDeserializer;import com.fasterxml.jackson.databind.KeyDeserializer;import com.fasterxml.jackson.databind.util.Converter; /** * Annotation use for configuring deserialization aspects, by attaching * to "setter" methods or fields, or to value classes. * When annotating value classes, configuration is used for instances * of the value class but can be overridden by more specific annotations * (ones that attach to methods or fields). ** An example annotation would be: *
* @JsonDeserialize(using=MySerializer.class, * as=MyHashMap.class, * keyAs=MyHashKey.class, * contentAs=MyHashValue.class * ) *** Something to note on usage: *
- *
- All other annotations regarding behavior during building should be on Builder * class and NOT on target POJO class: for example @JsonIgnoreProperties should be on * Builder to prevent "unknown property" errors. * *
- Similarly configuration overrides (see {@link com.fasterxml.jackson.databind.ObjectMapper#configOverride}) * should be targeted at Builder class, not target POJO class. * *
* Bogus type {@link Void} can be used to indicate that declared * type is used as is (i.e. this annotation property has no setting); * this since annotation properties are not allowed to have null value. *
* Note: if {@link #using} is also used it has precedence * (since it directly specified * deserializer, whereas this would only be used to locate the * deserializer) * and value of this annotation property is ignored. */ public Class> as() default Void.class; /** * Concrete type to deserialize keys of {@link java.util.Map} as, * instead of type otherwise declared. * Must be a subtype of declared type; otherwise an exception may be * thrown by deserializer. */ public Class> keyAs() default Void.class; /** * Concrete type to deserialize content (elements * of a Collection/array, values of Maps) values as, * instead of type otherwise declared. * Must be a subtype of declared type; otherwise an exception may be * thrown by deserializer. */ public Class> contentAs() default Void.class;}
以日期类型为例
@JsonDeserialize(using= DateJsonDeserializer.class) // Json ==> Bean,需要写到Setter方法上public void setCreateTime(Date createTime) { this.createTime = createTime;} @JsonSerialize(using= DateJsonSerializer.class) // Bean ==> Json,需要写到Getter方法上public Date getCreateTime() { return createTime;}
自定义转换方法
public class DateJsonDeserializer extends JsonDeserializer{ public static final SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override public Date deserialize(com.fasterxml.jackson.core.JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, com.fasterxml.jackson.core.JsonProcessingException { try { if(jsonParser!=null&&StringUtils.isNotEmpty(jsonParser.getText())){ return format.parse(jsonParser.getText()); }else { return null; } } catch(Exception e) { System.out.println(e.getMessage()); throw new RuntimeException(e); } } } public class DateJsonSerializer extends JsonSerializer { public static final SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeString(format.format(date)); } }
看完了这篇文章,相信你对"jackson在springboot中如何实现自定义参数转换器"有了一定的了解,如果想了解更多相关知识,欢迎关注行业资讯频道,感谢各位的阅读!