List to Json, сериализация

237
06 мая 2018, 21:43

Всем привет. И сразу же ВОПРОС: Как конвертировать List to Json

Если конвертирую один обьект Car в Json-obj то все хорошо

Car cars = carSrv.getById(1);
 Gson gson = new GsonBuilder().create();
 String jse = gson.toJson(cars);

При попытке проделать эту операцию со списком (List в Json)

 List<Car> cars = carSrv.getAll();
 Gson gson = new GsonBuilder().create();
 String jse = gson.toJson(cars);

Вылетает екзепшн:

    java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: org.hibernate.proxy.HibernateProxy. Forgot to register a type adapter?
    at com.google.gson.internal.bind.TypeAdapters$1.write(TypeAdapters.java:76)
    at com.google.gson.internal.bind.TypeAdapters$1.write(TypeAdapters.java:69)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
    at com.google.gson.internal.bind.ArrayTypeAdapter.write(ArrayTypeAdapter.java:93)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:112)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:239)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:112)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:239)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:112)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:239)
    at com.google.gson.Gson.toJson(Gson.java:661)
    at com.google.gson.Gson.toJson(Gson.java:640)
    at com.google.gson.Gson.toJson(Gson.java:595)
    at com.google.gson.Gson.toJson(Gson.java:575)
...

Использую Gson библиотеку:

        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.6.2</version>
        </dependency>

Гдето в сети нашел решение с указанием типа:

 List<Car> cars = carSrv.getAll();
 Gson gson = new GsonBuilder().create();
 Type listType = new TypeToken<List<Car>>() {}.getType();
String jse = gson.toJson(cars, listType);

НЕ ПОМОГЛО! тот же самій екзепшн

Нашел еще решение здесь и много его дублей :) Все же предполагаю, что проблема здесь не с хибернейтом, а с сериализацией

 List<Car> cars = carSrv.getAll();
 Gson gson = new GsonBuilder()
            .registerTypeAdapterFactory(HibernateProxyTypeAdapter.FACTORY)
            .create();
 String jse = gson.toJson(cars);

класс HibernateProxyTypeAdapter взял из примеров.

public class HibernateProxyTypeAdapter extends TypeAdapter<HibernateProxy> {
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
    @Override
    @SuppressWarnings("unchecked")
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        return (HibernateProxy.class.isAssignableFrom(type.getRawType()) ? (TypeAdapter<T>) new HibernateProxyTypeAdapter(gson) : null);
    }
};
private final Gson context;
private HibernateProxyTypeAdapter(Gson context) {
    this.context = context;
}
@Override
public HibernateProxy read(JsonReader in) throws IOException {
    throw new UnsupportedOperationException("Not supported");
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public void write(JsonWriter out, HibernateProxy value) throws IOException {
    if (value == null) {
        out.nullValue();
        return;
    }
    // Retrieve the original (not proxy) class
    Class<?> baseType = Hibernate.getClass(value);
    // Get the TypeAdapter of the original class, to delegate the serialization
    TypeAdapter delegate = context.getAdapter(TypeToken.get(baseType));
    // Get a filled instance of the original class
    Object unproxiedValue = ((HibernateProxy) value).getHibernateLazyInitializer()
            .getImplementation();
    // Serialize the value
    delegate.write(out, unproxiedValue);
}

}

НЕ ПОМОГЛО! екзепшн вида:

2018-мая-04 16:33:00.829 ERROR [http-nio-8080-exec-8] o.s.b.w.s.ErrorPageFilter - Forwarding to error page from request [/aes/by/id] due to exception [null]
java.lang.StackOverflowError: null
    at com.google.gson.internal.bind.TypeAdapters$11.write(TypeAdapters.java:317)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:112)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:239)
    at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:968)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:97)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:61)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:112)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:239)
    at ua.avk.carwash.adapter.HibernateProxyTypeAdapter.write(HibernateProxyTypeAdapter.java:54)
    at ua.avk.carwash.adapter.HibernateProxyTypeAdapter.write(HibernateProxyTypeAdapter.java:19)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:112)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:239)
    at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:968)

Вот сам класс Car, на всякий случай:

    @JsonInclude(JsonInclude.Include.NON_NULL)
@Entity
@Table(name = "Car")
public class Car implements Serializable, Storable {
    private static final long serialVersionUID = 1000000000000111L;
    public static final String GET_BY_NAME = "select e from Car e where e.name = ?1";
    public static final String GET_BY_TYPE = "select e from Car e where e.carType = ?1";
    public static final String GET_BY_NUMBER = "select e from Car e where e.number = ?1";
    public static final String GET_BY_CLIENT = "select e from Car e where e.client = ?1";
    private Long id;
    private String name;
    private String number;
    private CarType carType;
    private Client client;
    private List<Order> orderList = new ArrayList<>();
    @JsonView(Views.User.class)
    @JsonProperty("id")
    @Id
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name = "increment", strategy = "increment")
    @Column(name = "car_id", nullable = false)
    @Override
    public Long getId() {
        return id;
    }
    @Override
    public void setId(Long id) {
        this.id = id;
    }
    @JsonProperty("name")
    @JsonView(Views.User.class)
    @Size(max = 50, message = "{size.field}")
    @Column(name = "name", nullable = true, insertable = true, updatable = true, length = 50)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @JsonProperty("number")
    @JsonView(Views.User.class)
    @Size(max = 8, message = "The car number must be {min} to {max} characters in length.")
    @Column(name = "number", nullable = true, insertable = true, updatable = true, length = 8)
    public String getNumber() {
        return number;
    }
    public void setNumber(String number) {
        this.number = number;
    }
    @JsonProperty("cartype")
    @JsonView(Views.User.class)
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "type_id", nullable = true, insertable = true, updatable = true)
    public CarType getCarType() {
        return carType;
    }
    public void setCarType(CarType carType) {
        this.carType = carType;
    }
    @JsonProperty("client")
    @JsonView(Views.User.class)
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "client_id", nullable = true, insertable = true, updatable = true)
    public Client getClient() {
        return client;
    }
    public void setClient(Client client) {
        this.client = client;
    }
    //@Transient
    @JsonProperty("orders")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @JsonView(Views.Admin.class)
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "car")
    //@Column(name = "order_id")
    public List<Order> getOrderList() {
        return orderList;
    }
    public void setOrderList(List<Order> orderList) {
        this.orderList = orderList;
    }
    @Override
    public String toString() {
        return String.format("%d, %s, %s, %s, %s;", id, name, number, carType, client);
    }
    /**
     * The method Copy the object of the car
     *
     * @param u - the object of the car
     */
    public void copy(Car u) {
        this.setClient(u.getClient());
        this.setOrderList(u.getOrderList());
        this.setName(u.getName());
        this.setNumber(u.getNumber());
        this.setCarType(u.getCarType());
    }
    /**
     * Override hashCode for correct work equals
     *
     * @return hashCode
     */
    @Override
    public int hashCode() {
        return new HashCodeBuilder()
                .append(this.client)
                .append(this.name)
                .append(this.number)
                .append(this.carType)
                .toHashCode();
    }
    /**
     * Compares of the car
     *
     * @param obj for compare
     * @return true if equals
     */
    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Car))
            return false;
        if (obj == this)
            return true;
        Car u = (Car) obj;
        return new EqualsBuilder()
                .append(this.client, u.client)
                .append(this.name, u.name)
                .append(this.number, u.number)
                .append(this.carType, u.carType)
                .isEquals();
    }
}

ВОПРОС: Как конвертировать List to Json в данной ситуации

Answer 1

Как я понял библиотеке Gson тоже не понравились двунаправленные связи в сущностях. В борьбе с двух-направленными связями в сущностях или вот с этими екзепшинами:

java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: org.hibernate.proxy.HibernateProxy. Forgot to register a type adapter?

и возможным:

Infinity Exception

Который, кстати говоря, более понятно выражает суть проблемы!

Мне помогло:

  1. Замена библиотеки Gson на Jackson, а именно:

    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-core-asl</artifactId>
        <version>1.9.13</version>
    </dependency>
  2. Использование аннотаций @JsonIgnore или пару @JsonBackReference и @JsonManagedReference, о них можно прочесть здесь, здесь

    • @JsonManagedReference обычная сериализация:
    • @JsonIgnore, @JsonBackReference исключение из сериализации;

Я применял вот так:

Класс Car

@Entity
@Table(name = "Car")
public class Car implements Serializable, Storable {
    private static final long serialVersionUID = 1000000000000111L;
    public static final String GET_BY_NAME = "select e from Car e where e.name = ?1";
    public static final String GET_BY_TYPE = "select e from Car e where e.carType = ?1";
    public static final String GET_BY_NUMBER = "select e from Car e where e.number = ?1";
    public static final String GET_BY_CLIENT = "select e from Car e where e.client = ?1";
    private Long id;
    private String name="";
    private String number="";
    private CarType carType = new CarType();
    private Client client = new Client();
    private List<Order> orderList = new ArrayList<>();
    @JsonProperty("id")
    @Id
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name = "increment", strategy = "increment")
    @Column(name = "car_id", nullable = false)
    @Override
    public Long getId() {
        return id;
    }
    @Override
    public void setId(Long id) {
        this.id = id;
    }
    @JsonProperty("name")
    @Size(max = 50, message = "{size.field}")
    @Column(name = "name", nullable = true, insertable = true, updatable = true, length = 50)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @JsonProperty("number")
    @Size(max = 8, message = "The car number must be {min} to {max} characters in length.")
    @Column(name = "number", nullable = true, insertable = true, updatable = true, length = 8)
    public String getNumber() {
        return number;
    }
    public void setNumber(String number) {
        this.number = number;
    }
    @JsonProperty("cartype")
    @JsonBackReference
    @ManyToOne(fetch = FetchType.LAZY, optional = true)
    @JoinColumn(name = "type_id", nullable = true, insertable = true, updatable = true)
    public CarType getCarType() {
        return carType;
    }
    public void setCarType(CarType carType) {
        this.carType = carType;
    }
    @JsonProperty("client")
    @JsonBackReference
    @ManyToOne(fetch = FetchType.EAGER, optional = false)
    @JoinColumn(name = "client_id", nullable = true, insertable = true, updatable = true)
    public Client getClient() {
        return client;
    }
    public void setClient(Client client) {
        this.client = client;
    }
    @JsonProperty("orders")
    @JsonManagedReference
    //@Transient
    @OneToMany(fetch = FetchType.EAGER, mappedBy = "car")
    public List<Order> getOrderList() {
        return orderList;
    }
    public void setOrderList(List<Order> orderList) {
        this.orderList = orderList;
    }
    @Override
    public String toString() {
        return String.format("%d, %s, %s, %d, %d, %s", id, name, number, carType.getId(), client.getId(), orderList);
    }
    /**
     * The method Copy the object of the car
     *
     * @param u - the object of the car
     */
    public void copy(Car u) {
        this.setClient(u.getClient());
        this.setOrderList(u.getOrderList());
        this.setName(u.getName());
        this.setNumber(u.getNumber());
        this.setCarType(u.getCarType());
    }
    /**
     * Override hashCode for correct work equals
     *
     * @return hashCode
     */
    @Override
    public int hashCode() {
        return new HashCodeBuilder()
                .append(this.client)
                .append(this.name)
                .append(this.number)
                .append(this.carType)
                .toHashCode();
    }
    /**
     * Compares of the car
     *
     * @param obj for compare
     * @return true if equals
     */
    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Car))
            return false;
        if (obj == this)
            return true;
        Car u = (Car) obj;
        return new EqualsBuilder()
                .append(this.client, u.client)
                .append(this.name, u.name)
                .append(this.number, u.number)
                .append(this.carType, u.carType)
                .isEquals();
    }
}

Класс CarType

@Entity
@Table(name = "CarType")
public class CarType implements Serializable, Storable {
    private static final long serialVersionUID = 1000000000000112L;
    public static final String GET_BY_TYPE = "select e from CarType e where e.type = ?1";
    private Long id;
    private String type;
    private List<Car> carList = new ArrayList<>();
    private List<Price> prices = new ArrayList<>();
    @Id
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name = "increment", strategy = "increment")
    @Column(name = "car_type_id", nullable = false)
    @Override
    public Long getId() {
        return id;
    }
    @Override
    public void setId(Long id) {
        this.id = id;
    }
    @JsonProperty("type")
    @Size(max = 15, message = "{size.field}")
    @Column(name = "type", nullable = true, insertable = true, updatable = true, length = 15)
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }

    @JsonProperty("cars")
    @JsonManagedReference
    //@Transient
    @OneToMany(mappedBy = "carType")
    public List<Car> getCarList() {
        return carList;
    }
    public void setCarList(List<Car> carList) {
        this.carList = carList;
    }

    @JsonProperty("prices")
    @JsonManagedReference
    //@Transient
    @OneToMany(mappedBy = "type")
    public List<Price> getPrices() {
        return prices;
    }
    public void setPrices(List<Price> prices) {
        this.prices = prices;
    }
    @Override
    public String toString() {
        return String.format("%d, %s, %s, %s", id, type, carList, prices);
    }
    /**
     * The method Copy the object of the carList type
     *
     * @param u - the object of the carList type
     */
    public void copy(CarType u) {
        this.setCarList(u.getCarList());
        this.setPrices(u.getPrices());
        this.setType(u.getType());
    }
    /**
     * Override hashCode for correct work equals
     *
     * @return hashCode
     */
    @Override
    public int hashCode() {
        return new HashCodeBuilder()
                .append(this.carList)
                .append(this.prices)
                .append(this.type)
                .toHashCode();
    }
    /**
     * Compares of the carList type
     *
     * @param obj for compare
     * @return true if equals
     */
    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof CarType))
            return false;
        if (obj == this)
            return true;
        CarType u = (CarType) obj;
        return new EqualsBuilder()
                .append(this.carList, u.carList)
                .append(this.prices, u.prices)
                .append(this.type, u.type)
                .isEquals();
    }
}

Мне помогло - надеюсь поможет и Вам.

READ ALSO
Восстановление бинарного дерева

Восстановление бинарного дерева

Теорема: Бинарное дерево можно однозначно восстановить имея InOrder и PostOrder/PreOrder последовательности, если последовательности не содержат дубликатов

224
Анимация при прокрутке RecyclerView вниз

Анимация при прокрутке RecyclerView вниз

Использую анимацию при прокрутке RecyclerView

235
Selenium WebDriver. Java. Поиск не выдаёт все значения.

Selenium WebDriver. Java. Поиск не выдаёт все значения.

Начал изучать Selenium WebDriverНад одной проблемой уже два дня голову ломаю

208
Как подключится к сторонней встроенной Database H2

Как подключится к сторонней встроенной Database H2

У меня есть программа , в которой есть своя встроенная (Embedded H2) databaseЯ могу подключиться к ее консоли находясь непосредственно в самой программе

267