小编给大家分享一下jackson在springboot中如何实现自定义参数转换器,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!
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进行json和java bean转换时,可以使用注解自定义转换器进行转换。
方法注释中写了,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>
* @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 @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中如何实现自定义参数转换器”有了一定的了解,如果想了解更多相关知识,欢迎关注亿速云行业资讯频道,感谢各位的阅读!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。