jackson在springboot中的使用方式-自定义参数转换器
程序员文章站
2022-03-21 12:45:06
目录jackson自定义转换器@jsondeserialize注解源码springboot jackson使用-自定义参数转换器springboot中默认使用jackson,且实现了很多参数转换器,其...
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> * @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)); } }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。