0

I am trying to read the events from a large JSON file one-by-one using the Jackson JsonParser. I would like to store each event temporarily in an Object something like JsonObject or any other object which I later want to use for some further processing.

I was previously reading the JSON events one-by-one and storing them into my own custom context: Old Post for JACKSON JsonParser Context which is working fine. However, rather than context, I would like to store them into jsonObject or some other object one by one.

Following is my sample JSON file:

{
   "@context":"https://context.org/context.jsonld",
   "isA":"SchoolManagement",
   "format":"application/ld+json",
   "schemaVersion":"2.0",
   "creationDate":"2021-04-21T10:10:09+00:00",
   "body":{
      "members":[
         {
            "isA":"student",
            "name":"ABCS",
            "class":10,
            "coaching":[
              "XSJSJ",
              "IIIRIRI"
            ],
            "dob":"1995-04-21T10:10:09+00:00"
         },
         {
            "isA":"teacher",
            "name":"ABCS",
            "department":"computer science",
            "school":{
              "name":"ABCD School"
            },
            "dob":"1995-04-21T10:10:09+00:00"
         },
         {
            "isA":"boardMember",
            "name":"ABCS",
            "board":"schoolboard",
            "dob":"1995-04-21T10:10:09+00:00"
         }
      ]
   }
}

At a time I would like to store only one member such as student or teacher in my JsonObject.

Following is the code I have so far: What's the best way to store each event in an Object which I can later use for some processing. Then again clear that object and use it for the next event?

public class Main {

    private JSONObject eventInfo;
    private final String[] eventTypes = new String[] { "student", "teacher", "boardMember" };

    public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException, JAXBException, URISyntaxException {
        // Get the JSON Factory and parser Object
        JsonFactory jsonFactory = new JsonFactory();
        JsonParser jsonParser = jsonFactory.createParser(new File(Main.class.getClassLoader().getResource("inputJson.json").toURI()));
        JsonToken current = jsonParser.nextToken();

        // Check the first element is Object
        if (current != JsonToken.START_OBJECT) {
            throw new IllegalStateException("Expected content to be an array");
        }

        // Loop until the start of the EPCIS EventList array
        while (jsonParser.nextToken() != JsonToken.START_ARRAY) {
            System.out.println(jsonParser.getCurrentToken() + " --- " + jsonParser.getCurrentName());
        }

        // Goto the next token
        jsonParser.nextToken();

        // Call the method to loop until the end of the events file
        eventTraverser(jsonParser);
    }

    // Method which will traverse through the eventList and read event one-by-one
    private static void eventTraverser(JsonParser jsonParser) throws IOException {

        // Loop until the end of the EPCIS events file
        while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
            
            //Is there a possibility to store the complete object directly in an JSON Object or I need to again go through every token to see if is array and handle it accordingly as mentioned in my previous POST.
            
        }
    }
}
BATMAN_2008
  • 2,788
  • 3
  • 31
  • 98

1 Answers1

0

After trying some things I was able to get it working. I am posting the whole code as it can be useful to someone in the future cause I know how frustrating it is to find the proper working code sample:

public class Main
{
  public void xmlConverter (InputStream jsonStream) throws IOException,JAXBException, XMLStreamException
  {
    // jsonStream is the input JSOn which is normally passed by reading the JSON file
    
    // Get the JSON Factory and parser Object
    final JsonFactory jsonFactory = new JsonFactory ();
    final JsonParser jsonParser = jsonFactory.createParser (jsonStream);
    final ObjectMapper objectMapper = new ObjectMapper ();

    //To read the duplicate keys if there are any key duplicate json
    final SimpleModule module = new SimpleModule ();
      module.addDeserializer (JsonNode.class, new JsonNodeDupeFieldHandlingDeserializer ());
      objectMapper.registerModule (module);
      jsonParser.setCodec (objectMapper);

    // Check the first element is Object if not then invalid JSON throw error
    if (jsonParser.nextToken () != JsonToken.START_OBJECT)
      {
    throw new IllegalStateException ("Expected content to be an array");
      }

    while (!jsonParser.getText ().equals ("members"))
      {
    //Skipping the elements till members key
    // if you want you can do some process here
    // I am skipping for now
      }

    // Goto the next token
    jsonParser.nextToken ();

    while (jsonParser.nextToken () != JsonToken.END_ARRAY)
      {
    final JsonNode jsonNode = jsonParser.readValueAsTree ();

    //Check if the JsonNode is valid if not then exit the process
    if (jsonNode == null || jsonNode.isNull ())
      {
        System.out.println ("End Of File");
        break;
      }

    // Get the eventType
    final String eventType = jsonNode.get ("isA").asText ();

    // Based on eventType call different type of class
    switch (eventType)
      {
      case "student":
        final Student studentInfo =
          objectMapper.treeToValue (jsonNode, Student.class);
        //I was calling the JAXB Method as I was doing the JSON to XML Conversion
        xmlCreator (studentInfo, Student.class);
        break;
      case "teacher":
        final Teacher teacherInfo =
          objectMapper.treeToValue (jsonNode, Teacher.class);
        xmlCreator (teacherInfo, Teacher.class);
        break;
      }
      }

  }

  //Method to create the XML using the JAXB
  private void xmlCreator (Object eventInfo,
               Class eventType) throws JAXBException
  {
    private final StringWriter sw = new StringWriter ();

    // Create JAXB Context object
    JAXBContext context = JAXBContext.newInstance (eventType);

    // Create Marshaller object from JAXBContext
    Marshaller marshaller = context.createMarshaller ();

    // Print formatted XML
      marshaller.setProperty (Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

    // Do not add the <xml> version tag
      marshaller.setProperty (Marshaller.JAXB_FRAGMENT, Boolean.TRUE);

    // XmlSupportExtension is an interface that every class such as Student Teacher implements
    // xmlSupport is a method in XmlSupportExtension which has been implemented in all classes

    // Create the XML based on type of incoming event type and store in SW
      marshaller.marshal (((XmlSupportExtension) eventInfo).xmlSupport (),
              sw);

    // Add each event within the List
      eventsList.add (sw.toString ());

    // Clear the StringWritter for next event
      sw.getBuffer ().setLength (0);

  }
}

This is the class that overrides the JACKSON class. This can be used if your Json has duplicate JSON keys. Follow this post for the complete explnation if you need. If you dont need then skip this part and remove the part of the code module from the above class: Jackson @JsonAnySetter ignores values of duplicate key when used with Jackson ObjectMapper treeToValue method


@JsonDeserialize(using = JsonNodeDupeFieldHandlingDeserializer.class)
public class JsonNodeDupeFieldHandlingDeserializer extends JsonNodeDeserializer {

  @Override
  protected void _handleDuplicateField(JsonParser p, DeserializationContext ctxt, JsonNodeFactory nodeFactory, String fieldName,
      ObjectNode objectNode, JsonNode oldValue, JsonNode newValue) {

    ArrayNode asArrayValue = null;

    if (oldValue.isArray()) {
      asArrayValue = (ArrayNode) oldValue;
    } else {
      asArrayValue = nodeFactory.arrayNode();
      asArrayValue.add(oldValue);
    }
    asArrayValue.add(newValue);
    objectNode.set(fieldName, asArrayValue);
  }

}
BATMAN_2008
  • 2,788
  • 3
  • 31
  • 98