henry300
henry300

Reputation: 35

Parsing JSON in Java by the name of the key

I didn't find any topics on the same problem. Correct me if I am wrong.

The following JSON is the simplified version of the response I get back from an external API:

{    
    "vehicles": [
        {
            "car": {
                "color": "blue",
                "brand": "audi",
                "maxSpeed": 300,
                "releaseYear": 2016 
            }
        },
        {
            "car": {
                "color": "red",
                "brand": "bmw",
                "maxSpeed": 200,
                "releaseYear": 2012 
            }
        },
        {
            "motorcycle": {
                "color": "yellow",
                "brand": "yamaha",
                "maxSpeed": 300,
                "releaseYear": 2013 
            }
        }
    ]
}

So I get a list of vehicles and each element is an object that has one field named either car or motorcycle, no other options are possible. Both types of vehicles have exactly the same data fields . The only way to differentiate both types is by the name of the key in JSON

How I want to parse it:

In Java I have three objects:

abstract class Vehicle {
    String color;
    String brand;
    Integer maxSpeed;
    Integer releaseYear

    public boolean hasFourWheels();
}

class Car extends Vehicle {
    public boolean hasFourWheels() { return true; }
}

class Motorcycle extends Vehicle {
    public boolean hasFourWheels() { return false; }
}

Is it possible to get a list of Vehicles where each instance is either Car or Motorcycle?

Upvotes: 0

Views: 317

Answers (3)

Rax
Rax

Reputation: 375

Yes, it is possible.

In case you want something like getCarList and getMotorCycleList which return you list of car and list of motorcycle respectively after parsing the json:

  • Parse the JSON using com.google.gson.JsonParser
  • Then get the JsonArray by using "vehicles" as property name.
  • Iterate over the array and check if array element has a member by name "car". Accordingly create an instance of car or motorcycle, populate attributes and add that to respective list of either car or motorcycle.

Let me know in case code snippet needs to be added.

Upvotes: 1

Akceptor
Akceptor

Reputation: 1932

Looks very similar to what you asking: one superclass and a couple of subclasses. Use @JsonTypeInfo annotation: https://www.baeldung.com/jackson-inheritance

Upvotes: 0

Conffusion
Conffusion

Reputation: 4475

A solution I tried is using an intermediate class which maps more to the json structure:

import java.util.ArrayList;
import java.util.List;

import cars.Car;
import cars.Motorcycle;
import cars.Vehicle;


public class VehiclesHolder {

    List<VehicleHolder> vehicles=new ArrayList<>();

    public static class VehicleHolder {
        Car car;
        Motorcycle motorcycle;
        public Car getCar() {
            return car;
        }
        public void setCar(Car car) {
            this.car = car;
        }
        public Motorcycle getMotorcycle() {
            return motorcycle;
        }
        public void setMotorcycle(Motorcycle motorcycle) {
            this.motorcycle = motorcycle;
        }
    }

    public List<VehicleHolder> getVehiclesHolder() {
        return vehicles;
    }

    public void setVehiclesHolder(List<VehicleHolder> vehicles) {
        this.vehicles = vehicles;
    }
    public List<Vehicle> getVehicles()
    {
        List<Vehicle> result=new ArrayList<Vehicle>();
        for(VehicleHolder holder:vehicles)
        {
            result.add(holder.getCar()!=null?holder.getCar():holder.getMotorcycle());
        }
        return result;
    }
}

Use Jackson ObjectMapper to parse json to this class:

import java.io.IOException;
import java.util.List;
import cars.Vehicle;
import com.fasterxml.jackson.databind.ObjectMapper;

public class ParserMain {

    public static void main(String[] args) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        VehiclesHolder holder=objectMapper.readValue(ParserMain.class.getResourceAsStream("input.json"), VehiclesHolder.class);
        List<Vehicle> vehicles=holder.getVehicles();
    }
}

The vehicles variable at the end contains a list of Car and Motorcycle instances.

The ObjectMapper.readValue method exists in different flavours.

Last thing: maven dependencies used:

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.5.3</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.5.3</version>
    </dependency>

Upvotes: 1

Related Questions