ObjectMapper在处理尾随字符时不会失败

huangapple go评论63阅读模式
英文:

ObjectMapper doesn't fail on trailing characters

问题

我有以下的类:

public class Car {
    private String id;
    private String name;

    public Car() {
    }

    public Car(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

我使用它的方式如下:

String json = "{\"id\":\"1\", \"name\":\"hh\"} {\"id\":\"2\", \"name\":\"ccc\"}";

Car car;
try {
    ObjectMapper mapper = new ObjectMapper();
    car = mapper.readValue(json, new TypeReference<Car>() {
    });
} catch (IOException e) {
    car = null;
}

我预期它会失败,但实际上,我得到了输入中的第一个对象,即“第一个”汽车对象。

为什么会发生这种情况呢?

英文:

I'm having the following class:

public class Car{
private String id;
private String name;

public Car() {
}

public Car(String id, String name) {
    this.id = id;
    this.name = name;
}

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

}

and I use it like this:

String json = &quot;{\&quot;id\&quot;:\&quot;1\&quot;, \&quot;name\&quot;:\&quot;hh\&quot;} {\&quot;id\&quot;:\&quot;2\&quot;, \&quot;name\&quot;:\&quot;ccc\&quot;}&quot;;

    Car car;
    try {
        ObjectMapper mapper = new ObjectMapper();
        car = mapper.readValue(json, new TypeReference&lt;Car&gt;() {
        });
    } catch (IOException e) {
        car = null;
    }

I'm expecting it to fail but instead, I get the first object in the input, the "first" car object.

why is that happening?

答案1

得分: 2

你需要启用 FAIL_ON_TRAILING_TOKENS 功能以在这种情况下抛出异常:

ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS);

或者自版本 2.10 起:

ObjectMapper mapper = JsonMapper.builder()
        .enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)
        .build();

来自文档:

> 此功能确定绑定根值后数据绑定的行为。如果启用了该功能,将会多调用一次 JsonParser.nextToken() 来确保没有找到更多的标记
> (如果找到任何标记,将抛出 MismatchedInputException);如果禁用,将不再进行进一步的检查。该功能也可以称为 READ_FULL_STREAM
> 因为它实际上验证输入流只包含所需的用于绑定完整值的数据,不多也不少(除非数据格式支持可能的可忽略的空白或注释)。
>
> 该功能在默认情况下被禁用(因此不会对可能的尾随标记进行检查),这是为了保持向后兼容性。

你可以启用 FAIL_ON_* 系列中的所有功能,以使其尽可能严格。

英文:

You need to enable FAIL_ON_TRAILING_TOKENS feature to throw an exception in this case:

ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS);

or since version 2.10:

ObjectMapper mapper = JsonMapper.builder()
		.enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)
		.build();

From documentation:

> Feature that determines behaviour for data-binding after binding the
> root value. If feature is enabled, one more call to
> JsonParser.nextToken() is made to ensure that no more tokens are found
> (and if any is found, MismatchedInputException is thrown); if
> disabled, no further checks are made. Feature could alternatively be
> called READ_FULL_STREAM, since it effectively verifies that input
> stream contains only as much data as is needed for binding the full
> value, and nothing more (except for possible ignorable white space or
> comments, if supported by data format).
>
> Feature is disabled by default (so that no check is made for possible
> trailing token(s)) for backwards compatibility reasons.

You can enable all features from FAIL_ON_* family to be as strict as possible.

答案2

得分: 0

替代方案。
注意,您的类型引用不是`Car`,而是`Car`的`List`。

final ObjectMapper mapper = new ObjectMapper();
final TypeReference<List> typeReference = new TypeReference<List>() {};

final String json = "{"id":"1", "name":"hh"} {"id":"2", "name":"ccc"}";
List cars = null;

try {
cars = mapper.readValue(json, typeReference);
} catch (IOException e) {
e.printStackTrace(); // TODO - 请处理异常
cars = null;
}

System.out.println("Cars: " + cars);

将会打印出:

com.fasterxml.jackson.databind.exc.MismatchedInputException: 无法从START_OBJECT标记反序列化java.util.ArrayList<com.yk.training.backperssure.Car>的实例
at [Source: (String)"{"id":"1", "name":"hh"} {"id":"2", "name":"ccc"}"; line: 1, column: 1]
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1464)

// 更多堆栈跟踪...
Cars: null

英文:

Alternative.
Note, your type reference is not a Car, but a List of Cars.

final ObjectMapper mapper = new ObjectMapper();
final TypeReference&lt;List&lt;Car&gt;&gt; typeReference = new TypeReference&lt;List&lt;Car&gt;&gt;() {};


final String json = &quot;{\&quot;id\&quot;:\&quot;1\&quot;, \&quot;name\&quot;:\&quot;hh\&quot;} {\&quot;id\&quot;:\&quot;2\&quot;, \&quot;name\&quot;:\&quot;ccc\&quot;}&quot;;
List&lt;Car&gt; cars = null;

try {
    cars = mapper.readValue(json, typeReference);
} catch (IOException e) {
    e.printStackTrace();   // TODO - Please, handle it
    cars = null;
}

System.out.println(&quot;Cars: &quot; + cars);

It will print:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList&lt;com.yk.training.backperssure.Car&gt;` out of START_OBJECT token
 at [Source: (String)&quot;{&quot;id&quot;:&quot;1&quot;, &quot;name&quot;:&quot;hh&quot;} {&quot;id&quot;:&quot;2&quot;, &quot;name&quot;:&quot;ccc&quot;}&quot;; line: 1, column: 1]
	at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
	at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1464)

// More stack trace.,..\

Cars: null

huangapple
  • 本文由 发表于 2020年5月19日 17:43:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/61887954.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定