如何配置Gson对toJson的值进行额外的处理?
public class MyClass{
@SerializedName("qwerty")
@Mask(exposeFront=2, exposeRear=2, mask="*")
private String qwerty
}
假设MyClass#qwerty
的值为1234567890
,如何将Gson设置为输出{"qwerty":"12******90"}
发布于 2021-04-21 02:18:34
负责“普通”对象序列化和反序列化的@Masked
ReflectiveTypeAdapterFactory
无法增强以支持任何其他注释,如Gson。它只能使用@Expose
(间接通过排除策略)、@SerializedName
和其他一些注释,如@Since
和@Until
(也可以使用排除策略)。注意:默认情况下,文档中记录并支持这些注释。一般来说,Gson建议对声明类使用类型适配器MyClass
,但这也意味着您必须管理所有字段,并确保在类更改后更新相应的类型适配器。更糟糕的是,添加自定义类型适配器会使这些批注的支持丢失。
另一种解决方法是注入一个特殊的字符串类型适配器工厂,该工厂可以做到这一点,但由于它的注入机制,这是有限的,并且需要复制@Masked
注释值(如果您在代码中的其他地方使用该注释)和@JsonAdapter
中的类型适配器工厂配置。
public abstract class MaskedTypeAdapterFactory
implements TypeAdapterFactory {
private final int exposeFront;
private final int exposeRear;
private final char mask;
private MaskedTypeAdapterFactory(final int exposeFront, final int exposeRear, final char mask) {
this.exposeFront = exposeFront;
this.exposeRear = exposeRear;
this.mask = mask;
}
// must be "baked" into the class (name only represents the configuration)
public static final class _2_2_asterisk
extends MaskedTypeAdapterFactory {
private _2_2_asterisk() {
super(2, 2, '*');
}
}
@Override
@Nullable
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
if ( typeToken.getRawType() != String.class ) {
return null;
}
@SuppressWarnings("unchecked")
final TypeAdapter<String> delegate = (TypeAdapter<String>) gson.getAdapter(typeToken);
final TypeAdapter<String> typeAdapter = new TypeAdapter<String>() {
@Override
public void write(final JsonWriter out, final String value)
throws IOException {
// mask the value
final int length = value.length();
final char[] buffer = value.toCharArray();
for ( int i = exposeFront; i < length - exposeRear; i++ ) {
buffer[i] = mask;
}
out.value(new String(buffer));
}
@Override
public String read(final JsonReader in)
throws IOException {
return delegate.read(in);
}
}
.nullSafe();
@SuppressWarnings("unchecked")
final TypeAdapter<T> adapter = (TypeAdapter<T>) typeAdapter;
return adapter;
}
}
@NoArgsConstructor
@AllArgsConstructor
final class MyClass {
@SerializedName("qwerty")
@Mask(exposeFront = 2, exposeRear = 2, mask = "*")
// unfortunately, this must duplicate the @Mask annotation values
// since type adapter (factories) do not accept supplemental information
// and Java annotations can only accept compile-time constants
@JsonAdapter(MaskedTypeAdapterFactory._2_2_asterisk.class)
@SuppressWarnings("unused")
private String qwerty;
}
测试:
public final class MaskedTypeAdapterFactoryTest {
private static final Gson gson = new GsonBuilder()
.disableHtmlEscaping()
.disableInnerClassSerialization()
.create();
@Test
public void test() {
final String actual = gson.toJson(new MyClass("1234567890"));
final String expected = "{\"qwerty\":\"12******90\"}";
Assertions.assertEquals(expected, actual);
}
}
在Gson中,这可能是最健壮的方式。
https://stackoverflow.com/questions/67188120
复制