Hi,

Thanks a lot for your response. Sorry if you were unable to follow my 
question (stackoverflow <https://stackoverflow.com/q/69052269/7584240>). I 
am sure the problem is happening because point 2 mentioned by you but I am 
not understanding how to find a workaround for it.

I will try to make it a bit simple so you can understand provide some 
workaround for me (I have posted this on Stackoverflow as well so the code 
and text are a bit formatted for easy understanding 
https://stackoverflow.com/q/69052269/7584240):

I am using Jackson to deserialize a JSON. The input JSON can be of 2 types 
`CustomerDocument` or `Single Customer`. `CustomerDocument` will have a 
`CustomerList` which can consist of a huge number of `Customer` and the 
`Single Customer` will have just a `Single Customer`. Hence, the Jackson 
has to handle 2 things:

1. Identify if the provided JSON is a `CustomerDocument`, if so then 
deserialize the elements in `CustomerList` one by one rather than storing 
the whole thing into `List` so as to reduce the memory usage.
2. Identify if the provided JSON is a `single Customer` and if so then 
deserialize the `customer` directly.

I am able to achieve this and everything is working as expected but when I 
provide the `CustomerDocument` then it's unable to read the `@Context` 
key-value pair as it has been already read during the check for single 
`Customer` (as mentioned by you in point 2). I guess the below code would 
make the problems clear:

Following is the JSON I am trying to deserialize:
```
{
  "@context": [
    "https://stackoverflow.com";,
    {
      "example": "https://example.com";
    }
  ],
  "isA": "CustomerDocument",
  "customerList": [
    {
      "isA": "Customer",
      "name": "Batman",
      "age": "2008"
    }
  ]
}
```

Following is my Customer POJO class:
```
@Data
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = 
JsonTypeInfo.As.PROPERTY, visible = true, property = "isA")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Customer implements BaseResponse {
    private String isA;
    private String name;
    private String age;
}


@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = 
JsonTypeInfo.As.PROPERTY, visible = true, property = "isA")
@JsonSubTypes({
        @JsonSubTypes.Type(value = Customer.class, name = "Customer")})
interface BaseResponse {
}
```

Following is my `Main` class which will read the `JSON InputStream` and 
make the decision whether the provided input JSON is `CustomerList` or 
`Single Customer` and then deserialize accordingly:
```
public class JacksonMain {
    public static void main(String[] args) throws IOException {
        final InputStream jsonStream = 
JacksonMain.class.getClassLoader().getResourceAsStream("Customer.json");
        final JsonParser jsonParser = new 
JsonFactory().createParser(jsonStream);
        final ObjectMapper objectMapper = new ObjectMapper();
        jsonParser.setCodec(objectMapper);

        //Goto the start of the document
        jsonParser.nextToken();

        try {
            BaseResponse baseResponse = objectMapper.readValue(jsonParser, 
BaseResponse.class);
            System.out.println("SINGLE EVENT INPUT" + 
baseResponse.toString());
        } catch (Exception e) {
            System.out.println("LIST OF CUSTOMER INPUT");
            //Go until the customerList has been reached
            while (!jsonParser.getText().equals("customerList")) {
                System.out.println("Current Token Name : " + 
jsonParser.getCurrentName());
                if (jsonParser.getCurrentName() != null && 
jsonParser.getCurrentName().equalsIgnoreCase("@context")) {
                    System.out.println("WITHIN CONTEXT");
                }
                jsonParser.nextToken();
            }
            jsonParser.nextToken();

            //Loop through each object within the customerList and 
deserilize them
            while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
                final JsonNode customerNode = jsonParser.readValueAsTree();
                final String eventType = customerNode.get("isA").asText();
                Object event = objectMapper.treeToValue(customerNode, 
BaseResponse.class);
                System.out.println(event.toString());
            }
        }
    }
}
```

Following is the output I am getting:

```
LIST OF CUSTOMER INPUT
Current Token Name : isA
Customer(isA=Customer, name=Batman, age=2008)
```

As we can see it's printing only `Current Token Name: isA` I would expect 
it to print `isA` and `@Context` because it's present before the `isA`. But 
I am aware that it's not printing because it has already passed that due to 
the following line of code in `try` block:
```
BaseResponse baseResponse = objectMapper.readValue(jsonParser, 
BaseResponse.class);
```

Can someone please suggest to me how can I achieve this and is there a 
better workaround for this issue?

Please note:
1. The `CustomerList` can have a lot of `Customers` hence I do not want to 
store the whole `CustomerList` into some `List` as it can take a lot of 
memories. Hence, I am using `JsonParser` so I can read one `JsonToken` at a 
time.
2. Also, I do not want to create a `CustomerList` class rather than that I 
want to read one `Customer` at a time and deserialize it.
3. The JSON structure cannot be modified as it's coming from another 
application and it's a standard format for my application.

On Sunday, 5 September 2021 at 03:34:25 UTC+5:30 [email protected] wrote:

> Unfortunately this example is quite long so I cannot quite understand the 
> intent; but I have 2 suggestions in trying to trace the behavior.
>
> 1. Instead of assuming current token type to be certain thing, verify what 
> the token is: some methods (like "parser.getText()" and 
> "parser.getCurrentName()") are applicable to different token types -- and 
> just because you have "current name" does not necessarily mean you have 
> FIELD_NAME token (in fact it is the value of last name for token following)
> 2. When a parse exception is thrown, underlying JsonParser is NOT 
> guaranteed to be in a consistent state. Parser should still have 
> information about the last successfully decoded token (but not in case 
> where we are half-way through decoding a new one, and fail), and the 
> location where the problem is encountered. But it SHOULD NOT be assumed 
> that you can further parse content successfully. It is possible no content 
> is available; internal state may be corrupt and so forth.
>
> -+ Tatu +-
>
>
> On Thu, Sep 2, 2021 at 11:44 PM Aravinda Baliga B <[email protected]> 
> wrote:
>
>> I am building a Jackson deserialization application that can handle the 
>> deserialization of `CustomerList` and `Customer`. Users can provide any 
>> input and based on the input the code will make the decision whether the 
>> provided input JSON is `CustomerList` or `Single Customer`.
>>
>> Everything is working as expected apart from one small thing. When I 
>> provide the `CustomerList` JSON then it would skip the first `key value` 
>> pair. In my case, it's skipping the `@Context`.
>>
>> Following is the `JSON` i am trying to deserialize:
>> ```
>> {
>>   "@context": [
>>     "https://stackoverflow.com";,
>>     {
>>       "example": "https://example.com";
>>     }
>>   ],
>>   "isA": "CustomerDocument",
>>   "customerList": [
>>     {
>>       "isA": "Customer",
>>       "name": "Batman",
>>       "age": "2008"
>>     }
>>   ]
>> }
>> ```
>>
>> Following is my Customer POJO class:
>> ```
>> @Data
>> @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = 
>> JsonTypeInfo.As.PROPERTY, visible = true, property = "isA")
>> @JsonInclude(JsonInclude.Include.NON_NULL)
>> public class Customer implements BaseResponse {
>>     private String isA;
>>     private String name;
>>     private String age;
>> }
>>
>>
>> @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = 
>> JsonTypeInfo.As.PROPERTY, visible = true, property = "isA")
>> @JsonSubTypes({
>>         @JsonSubTypes.Type(value = Customer.class, name = "Customer")})
>> interface BaseResponse {
>> }
>> ```
>>
>> Following is the Main:
>> ```
>> public class JacksonMain {
>>     public static void main(String[] args) throws IOException {
>>         final InputStream jsonStream = 
>> JacksonMain.class.getClassLoader().getResourceAsStream("Customer.json");
>>         final JsonParser jsonParser = new 
>> JsonFactory().createParser(jsonStream);
>>         final ObjectMapper objectMapper = new ObjectMapper();
>>         jsonParser.setCodec(objectMapper);
>>
>>         //Goto the start of the document
>>         jsonParser.nextToken();
>>
>>         try {
>>             BaseResponse baseResponse = 
>> objectMapper.readValue(jsonParser, BaseResponse.class);
>>             System.out.println("SINGLE EVENT INPUT" + 
>> baseResponse.toString());
>>         } catch (Exception e) {
>>             System.out.println("LIST OF CUSTOMER INPUT");
>>             //Go until the customerList has been reached
>>             while (!jsonParser.getText().equals("customerList")) {
>>                 System.out.println("Current Token Name : " + 
>> jsonParser.getCurrentName());
>>                 if (jsonParser.getCurrentName() != null && 
>> jsonParser.getCurrentName().equalsIgnoreCase("@context")) {
>>                     System.out.println("WITHIN CONTEXT");
>>                 }
>>                 jsonParser.nextToken();
>>             }
>>             jsonParser.nextToken();
>>
>>             //Loop through each object within the customerList and 
>> deserilize them
>>             while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
>>                 final JsonNode customerNode = 
>> jsonParser.readValueAsTree();
>>                 final String eventType = customerNode.get("isA").asText();
>>                 Object event = objectMapper.treeToValue(customerNode, 
>> BaseResponse.class);
>>                 System.out.println(event.toString());
>>             }
>>         }
>>     }
>> }
>> ```
>>
>> When I run the application I get the following response:
>> ```
>> LIST OF CUSTOMER INPUT
>> Current Token Name : isA
>> Customer(isA=Customer, name=Batman, age=2008)
>> ```
>>
>> As we can see it's printing only `Current Token Name: isA` I would expect 
>> it to print `isA and @Context` because it's present before the `isA`. 
>>
>> The weird thing that I am seeing is that if I switch the places of `isA` 
>> and `@context` in my `JSON` something like this:
>> ```
>> {
>>   "isA": "CustomerDocument",
>>   "@context": [
>>     "https://stackoverflow.com";,
>>     {
>>       "example": "https://example.com";
>>     }
>>   ],
>>   "customerList": [
>>     {
>>       "isA": "Customer",
>>       "name": "Batman",
>>       "age": "2008"
>>     }
>>   ]
>> }
>> ```
>>
>> Then I get the output like this, As you can see now it's reading the 
>> `@context` and `isA` both.
>> ```
>> LIST OF CUSTOMER INPUT
>> Current Token Name : isA
>> Current Token Name : @context
>> WITHIN CONTEXT
>> Current Token Name : @context
>> WITHIN CONTEXT
>> Current Token Name : null
>> Current Token Name : null
>> Current Token Name : example
>> Current Token Name : example
>> Current Token Name : null
>> Current Token Name : @context
>> WITHIN CONTEXT
>> Customer(isA=Customer, name=Batman, age=2008)
>> ```
>>
>> Since it's working in the second case I am thinking it's not an issue 
>> with my code. But I am not sure what's causing the issue for it to not read 
>> in the `firstcase` (with `@context` first and `isA` second).  Can someone 
>> please help me understand this issue and provide some workaround as I am 
>> trying since yesterday to figure out the problem? Is this a bug in Jackson?
>>
>> Please note:
>> The JSON is out of my control as it's coming from another application. 
>> Provided JSON is a replica of my actual application JSON.
>>
>> The second JSON that I can feed to the application is the direct customer 
>> rather than a list: (with the current code this is working perfectly)
>> ```
>> {
>>   "@context": [
>>     "https://stackoverflow.com";,
>>     {
>>       "example": "https://example.com";
>>     }
>>   ],
>>   "isA": "Customer",
>>   "name": "Batman",
>>   "age": "2008"
>> }
>>
>> ```
>>
>> Can someone please help me understand why Jackson is skipping the 
>> `@context` when provided first and provide some workaround as I am trying 
>> since yesterday to figure out the problem? Is this a bug in Jackson?
>>
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "jackson-user" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to [email protected].
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/jackson-user/8b99e386-325a-45a7-9616-74ec142b45c4n%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/jackson-user/8b99e386-325a-45a7-9616-74ec142b45c4n%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"jackson-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/jackson-user/d8790fc3-3aec-4b42-8662-f4895dc568acn%40googlegroups.com.

Reply via email to