温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

jackson在springboot中如何实现自定义参数转换器

发布时间:2021-10-11 16:34:15 来源:亿速云 阅读:413 作者:小新 栏目:开发技术

小编给大家分享一下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

@Configuration public 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;     } }

日期对象的转换

@JsonComponent public class DateDeserializer extends JsonDeserializer<Date> implements Converter<String, Date> {     @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));     } } @JsonComponent public class DateSerializer extends JsonSerializer<Date> implements Converter<Date,String> {     @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 <V> 枚举实际值的数据类型  */ public interface IEnum<V> {     //枚举实际值     V getValue();     static<T extends IEnum> T getBean(String value,Class<T> 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=>对象  */ @JsonComponent public class EnumDeserializer<T extends IEnum> extends JsonDeserializer<T> implements ContextualDeserializer{     private Class<T> targetClass = null;     public EnumDeserializer() {     }     public EnumDeserializer(Class<T> 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<T> targetClass = (Class<T>) ctxt.getContextualType().getRawClass();         return new EnumDeserializer(targetClass);     } } /**  * 序列化,将enum枚举转为json  * @author chenzy  * @since 2019.12.19  */ @JsonComponent public class EnumSerializer<T extends IEnum> extends JsonSerializer<T> {     @Override     public void serialize(T value, JsonGenerator gen, SerializerProvider serializers) throws IOException {         Optional<T> data = Optional.of(value);         if (data.isPresent()) {//非空             gen.writeObject(data.get().getValue());         } else { //            gen.writeString("");         }     } }

下面才是真正的转换器

/**  * IEnum=>str  */ @Component public class Enum2StrConverter<T extends IEnum<?>> implements ConditionalConverter,Converter<T, String>{     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  */ @Component public class Str2EnumConverte implements ConverterFactory<String, IEnum> {     @Override     public <T extends IEnum> Converter<String, T> getConverter(Class<T> targetType) {         return new Str2Enum(targetType);     }     private static class Str2Enum<T extends IEnum> implements Converter<String, T> {         private final Class<T> enumType;         public Str2Enum(Class<T> 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  */ @Configuration public 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).  *<p>  * An example annotation would be:  *<pre>  *  &#64;JsonDeserialize(using=MySerializer.class,  *    as=MyHashMap.class,  *    keyAs=MyHashKey.class,  *    contentAs=MyHashValue.class  *  )  *</pre>  *<p>  * Something to note on usage:  *<ul>  * <li>All other annotations regarding behavior during building should be on <b>Builder</b>  *    class and NOT on target POJO class: for example &#64;JsonIgnoreProperties should be on  *    Builder to prevent "unknown property" errors.  *  </li>  * <li>Similarly configuration overrides (see {@link com.fasterxml.jackson.databind.ObjectMapper#configOverride})  *    should be targeted at Builder class, not target POJO class.  *  </li>  * </ul>  *  */ @Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @com.fasterxml.jackson.annotation.JacksonAnnotation public @interface JsonDeserialize {     // // // Annotations for explicitly specifying deserialize/builder       /**      * Deserializer class to use for deserializing associated value.      * Depending on what is annotated,      * value is either an instance of annotated class (used globablly      * anywhere where class deserializer is needed); or only used for      * deserializing property access via a setter method.      */     @SuppressWarnings("rawtypes") // to work around JDK8 bug wrt Class-valued annotation properties     public Class<? extends JsonDeserializer> using()         default JsonDeserializer.None.class;       /**      * Deserializer class to use for deserializing contents (elements      * of a Collection/array, values of Maps) of annotated property.      * Can only be used on instances (methods, fields, constructors),      * and not value classes themselves.      */     @SuppressWarnings("rawtypes") // to work around JDK8 bug wrt Class-valued annotation properties     public Class<? extends JsonDeserializer> contentUsing()         default JsonDeserializer.None.class;       /**      * Deserializer class to use for deserializing Map keys      * of annotated property.      * Can only be used on instances (methods, fields, constructors),      * and not value classes themselves.      */     public Class<? extends KeyDeserializer> keyUsing()         default KeyDeserializer.None.class;       /**      * Annotation for specifying if an external Builder class is to      * be used for building up deserialized instances of annotated      * class. If so, an instance of referenced class is first constructed      * (possibly using a Creator method; or if none defined, using default      * constructor), and its "with-methods" are used for populating fields;      * and finally "build-method" is invoked to complete deserialization.      */     public Class<?> builder() default Void.class;       // // // Annotations for specifying intermediate Converters (2.2+)          /**      * Which helper object (if any) is to be used to convert from Jackson-bound      * intermediate type (source type of converter) into actual property type      * (which must be same as result type of converter). This is often used      * for two-step deserialization; Jackson binds data into suitable intermediate      * type (like Tree representation), and converter then builds actual property      * type.      *      * @since 2.2      */     @SuppressWarnings("rawtypes") // to work around JDK8 bug wrt Class-valued annotation properties     public Class<? extends Converter> converter() default Converter.None.class;       /**      * Similar to {@link #converter}, but used for values of structures types      * (List, arrays, Maps).      *      * @since 2.2      */     @SuppressWarnings("rawtypes") // to work around JDK8 bug wrt Class-valued annotation properties     public Class<? extends Converter> contentConverter() default Converter.None.class;              // // // Annotations for explicitly specifying deserialization type     // // // (which is used for choosing deserializer, if not explicitly     // // // specified       /**      * Concrete type to deserialize values as, instead of type otherwise      * declared. Must be a subtype of declared type; otherwise an      * exception may be thrown by deserializer.      *<p>      * 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.      *<p>      * 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<Date> {     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<Date> {     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中如何实现自定义参数转换器”有了一定的了解,如果想了解更多相关知识,欢迎关注亿速云行业资讯频道,感谢各位的阅读!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI