Java 反序列化JSON时如何区分not PROFERED和null
我们从前端发送JSON字符串作为java代码的输入。Java端使用Gson将其转换为bean。现在,我的前端人员向我提出以下要求:Java 反序列化JSON时如何区分not PROFERED和null,java,json,generics,serialization,gson,Java,Json,Generics,Serialization,Gson,我们从前端发送JSON字符串作为java代码的输入。Java端使用Gson将其转换为bean。现在,我的前端人员向我提出以下要求: 有时他希望传递一个新值,后端只需将其写入数据库 有时他希望传递no值,这告诉后端不要对该值做任何事情 有时,他希望传递一个null,它告诉后端重置为某个“默认值”(后端已知,但前端不关心) 它还应适用于字符串、数字、布尔值等 我们想出了这个主意: import static org.hamcrest.Matchers.is; import static org.
- 有时他希望传递一个新值,后端只需将其写入数据库
- 有时他希望传递no值,这告诉后端不要对该值做任何事情
- 有时,他希望传递一个null,它告诉后端重置为某个“默认值”(后端已知,但前端不关心)
- 它还应适用于字符串、数字、布尔值等
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.lang.reflect.Type;
import java.util.Objects;
import org.junit.Test;
import com.google.gson.*;
class ResetableValue<T> {
private static enum Content {
VALUE, RESET, NOT_PROVIDED
};
private final T value;
private final Content content;
public ResetableValue(T value) {
this(value, Content.VALUE);
}
private ResetableValue(T value, Content content) {
this.value = value;
this.content = content;
}
static <T> ResetableValue<T> asReset() {
return new ResetableValue<>(null, Content.RESET);
}
static <T> ResetableValue<T> asNotProvided() {
return new ResetableValue<>(null, Content.NOT_PROVIDED);
}
T getValue() {
if (content != Content.VALUE) {
throw new IllegalStateException("can't provide value for " + content);
}
return value;
}
boolean isReset() {
return content == Content.RESET;
}
boolean isNotProvided() {
return content == Content.NOT_PROVIDED;
}
@Override
public String toString() {
if (content == Content.VALUE) {
return Objects.toString(value);
}
return content.toString();
}
}
class ResetableValueDeserializer implements JsonDeserializer<ResetableValue<String>> {
public ResetableValue<String> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return new ResetableValue<String>(json.getAsJsonPrimitive().getAsString());
}
}
class ExampleBean {
private ResetableValue<String> property = ResetableValue.asNotProvided();
public ResetableValue<String> getProperty() {
if (property == null) {
return ResetableValue.asReset();
}
return property;
}
@Override
public String toString() {
return "property: " + Objects.toString(property);
}
}
public class GsonStuffTest {
Gson gson = new GsonBuilder().registerTypeAdapter(ResetableValue.class, new ResetableValueDeserializer()).create();
@Test
public void testValue() {
String serializedContent = "{\"property\":\"foo\"}";
ExampleBean bean = gson.fromJson(serializedContent, ExampleBean.class);
assertThat(bean.getProperty().getValue(), is("foo"));
}
@Test
public void testIsNotProvided() {
String serializedContent = "{}";
ExampleBean bean = gson.fromJson(serializedContent, ExampleBean.class);
assertThat(bean.getProperty().isNotProvided(), is(true));
}
@Test
public void testIsReset() {
String serializedContent = "{\"property\":null}";
ExampleBean bean = gson.fromJson(serializedContent, ExampleBean.class);
assertThat(bean.getProperty().isReset(), is(true));
}
}
import static org.hamcrest.Matchers.is;
导入静态org.junit.Assert.assertThat;
导入java.lang.reflect.Type;
导入java.util.Objects;
导入org.junit.Test;
导入com.google.gson.*;
类可重置值{
私有静态枚举内容{
值,重置,未提供
};
私人最终T值;
私人最终内容;
公共可重置值(T值){
这(价值、内容、价值);
}
私有可重置值(T值、内容){
这个值=值;
this.content=内容;
}
静态可重置值asReset(){
返回新的可重置值(null,Content.RESET);
}
静态可重置值AsNotProvidered(){
返回新的可重置值(空,内容。未提供);
}
T getValue(){
if(content!=content.VALUE){
抛出新的IllegalStateException(“无法为“+内容”提供值);
}
返回值;
}
布尔isReset(){
返回内容==content.RESET;
}
布尔值未提供(){
返回内容==content.NOT_提供;
}
@凌驾
公共字符串toString(){
if(content==content.VALUE){
返回Objects.toString(值);
}
返回content.toString();
}
}
类ResetableValueDeserializer实现JsonDeserializer{
公共可重置值反序列化(JsonElement json,类型typeOfT,JsonDeserializationContext)
抛出JsonParseException{
返回新的可重置值(json.getAsJsonPrimitive().getAsString());
}
}
类ExampleBean{
private ResetableValue属性=ResetableValue.asNotProvided();
公共可重置值getProperty(){
if(属性==null){
返回ResetableValue.asReset();
}
归还财产;
}
@凌驾
公共字符串toString(){
返回“property:+Objects.toString(property);
}
}
公共类gsonstuff测试{
Gson Gson=new GsonBuilder().registerTypeAdapter(ResetableValue.class,new ResetableValueDeserializer()).create();
@试验
公共void testValue(){
字符串serializedContent=“{\”属性\:\“foo\”}”;
ExampleBean=gson.fromJson(serializedContent,ExampleBean.class);
资产(bean.getProperty().getValue(),是(“foo”);
}
@试验
提供的公共无效测试(){
字符串serializedContent=“{}”;
ExampleBean=gson.fromJson(serializedContent,ExampleBean.class);
断言(bean.getProperty().isNotProvidered(),is(true));
}
@试验
公共无效测试集(){
String serializedContent=“{\'属性\”:null}”;
ExampleBean=gson.fromJson(serializedContent,ExampleBean.class);
断言(bean.getProperty().isReset()为(true));
}
}
请注意:这个想法当然是在一个bean中有多个不同类型的字段ResetableValue
。然后一个字段可能关心一个值,一个被省略,另一个被设置为null
问题:
- 上面的例子“有效”——但我真的不喜欢这样一个事实:我必须在bean的
方法中处理“reset”情况。这意味着:仅拥有自定义反序列化器是不够的,我还需要将该特殊检查放入任何getter方法中。那么:有没有更优雅的解决方案?是否有办法让Gson区分“属性未显示”和“属性设置为空”getProperty()
- 上述示例声称是通用的;但显然,反序列化程序代码只适用于字符串属性。有没有办法让这个“真正通用”呢
getProperty
似乎有一个冗余检查:它不应该检查null
,只要在任何情况下返回property
字段,前提是Gson设法实例化它
上述示例声称是通用的;但显然,反序列化程序代码只适用于字符串属性。有没有办法让这个“真正通用”呢
是的,通过类型适配器工厂和类型适配器(关于后者:JsonSerializer
和JsonDeserializer
类使用JSON树消耗更多内存,但类型适配器是流式的,消耗更少)
让我们假设你有一个通用的三态值持有者,如下所示。 我还将隐藏构造函数,使其更流畅,并封装其实例化(或未实例化)的方式
最终类值{
私有静态最终值noValue=新值(State.NO_值,null);
私有的