Gson deserialize json. java.lang.RuntimeException: Не удалось вызвать общедоступный com.derp.procedure.model.SkeletonElement() без аргументов] с основной причиной

Это мой первый раз с json и java. Я проверил много вопросов/сообщений с той же ошибкой, что и моя. Но не нашли ничего полезного.

Я уверен, что мне нужно добавить конструктор args. Я ушел, но мне это не помогло. По-прежнему происходит одна и та же ошибка. Это может работать так. Я думаю, что это связано с полным завершением моего кода.

Ошибка:

SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/derp] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: Failed to invoke public com.derp.procedure.model.SkeletonElement() with no args] with root cause java.lang.InstantiationException

StackTrace:

gru 19, 2014 8:27:50 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/derp] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: Failed to invoke public com.derp.procedure.model.SkeletonElement() with no args] with root cause
java.lang.InstantiationException
    at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:48)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
    at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:104)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:186)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:81)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:60)
    at com.google.gson.Gson.fromJson(Gson.java:810)
    at com.google.gson.Gson.fromJson(Gson.java:775)
    at com.google.gson.Gson.fromJson(Gson.java:724)
    at com.derp.procedure.model.SkeletonElement.toObject(SkeletonElement.java:38)
    at com.derp.procedure.model.Skeleton.setSkeletonElements(Skeleton.java:53)
    at com.derp.procedure.controller.ProcedureController.elementsAssignmentSubmit(ProcedureController.java:81)
    at com.derp.procedure.controller.ProcedureController$$FastClassBySpringCGLIB$$35de90ba.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:266)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
    at com.derp.procedure.controller.ProcedureController$$EnhancerBySpringCGLIB$$fe2945ed.elementsAssignmentSubmit(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:781)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:721)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
    at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:879)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:136)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:526)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1078)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:655)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:146)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:279)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

Мои классы java:

Общий расширенный класс модели:

package com.derp.generic.model;

import java.io.IOException;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;

@MappedSuperclass
public abstract class GenericModel<T extends GenericModel<?>> {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;


    public long getId() {return id;}
    public void setId(long id) {this.id = id;}

    public GenericModel() {
    }
    // a toString method that can be used in any class.
    // uses reflection to dynamically print java class field
    // values one line at a time.
    @Override
    public String toString() {
      return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
    }
    public String toJson() {
        ObjectMapper jsonMapper = new ObjectMapper();
        try {
            return jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(this);
        } catch (JsonGenerationException e) {
            e.printStackTrace();
            return null;
        } catch (JsonMappingException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
    //public GenericModel<T> toObject(String jsonObject) {
        //Suggested by stackOverflowComunity at:
        //https://stackoverflow.com/info/27532206/java-create-list-of-objects-from-json-string-with-jackson
        public <T> T toObject(String jsonObject) {
        ObjectMapper jsonMapper = new ObjectMapper();
        try {
            //GenericModel<T> t = jsonMapper.readValue(jsonObject, GenericModel.class);
            T t = (T) jsonMapper.readValue(jsonObject, GenericModel.class);
            //return t;
            return t;
        } catch (JsonGenerationException e) {
            e.printStackTrace();
            return null;
        } catch (JsonMappingException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

}   

Общий иерархический класс, который расширяет общую модель:

package com.derp.generic.model;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.FetchType;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;
import javax.persistence.OneToMany;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;



@MappedSuperclass
public abstract class GenericHierarchicalModel<T extends GenericHierarchicalModel<T>> extends GenericModel<T> {
    private String name;
    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private T parent;
    @OneToMany(mappedBy = "parent")
    private List<T> children;

    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public T getParent() {return parent;}
    public void setParent(T parent) {this.parent = parent;}
    public List<T> getChildren() {return children;}
    public void setChildren(List<T> children) {this.children = children;}

    public GenericHierarchicalModel() {
        super();
    }
    @Override
    public String toJson() {
        return "{\"title\":\"" + this.name + "\", \"id\":\"" + this.getId() + "\", \"children\": [" + listToJson(this.getChildren()) + "]}";
    }
    public String listToJson(List<T> children) {
        String json = "";
        for(int i=0; i<children.size(); i++) {
            json = json + children.get(i).toJson();
            if(children.size()!=i+1) {
                json = json + ", ";
            }
        }
        return json;
    }
//  @Override
//  public GenericHierarchicalModel<T> toObject(String jsonObject) {
//      int start = 0; // '(' position in string
//      int end = 0; // ')' position in string
//      for(int i = 0; i < jsonObject.length(); i++) { 
//          if(jsonObject.charAt(i) == '{') // Looking for '{' position in string
//             start = i;
//          else if(jsonObject.charAt(i) == '}') // Looking for '}' position in  string
//             end = i;
//      }
//      String number = jsonObject.substring(start+1, end); // you take value between start and end
//      System.out.println(number);
//      return null;
//  }
}

Класс модели, который я пытаюсь десериализовать из списка объектов json:

package com.derp.procedure.model;

import java.io.IOException;
import java.util.List;

import javax.persistence.DiscriminatorColumn;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;

import com.derp.generic.model.GenericHierarchicalModel;
import com.derp.generic.model.GenericModel;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

@Entity
@Table(name="procedure__SkeletonElement")
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="type")
public abstract class SkeletonElement extends GenericHierarchicalModel<SkeletonElement> {
    @Transient
    public String getDecriminatorValue() {
        return this.getClass().getSimpleName();
    }
    @Override
    public String toJson() {
        return "{\"title\":\"" + this.getName() + "\", \"id\":\"" + this.getId() + "\", \"type\":\"" + this.getDecriminatorValue() + "\", \"children\": [" + listToJson(this.getChildren()) + "]}";
    }
    public List<SkeletonElement> toObject(String jsonObject) {
        Gson gson = new Gson(); // Or use new GsonBuilder().create();
        //SkeletonElement[] target2 = gson.fromJson(jsonObject, SkeletonElement[].class);
        List<SkeletonElement> target2 = gson.fromJson(jsonObject, new TypeToken<List<SkeletonElement>>(){}.getType());

        return target2;
    }
    public SkeletonElement() {
        super();
    }
}

И класс, содержащий коллекцию объекта, который я пытаюсь десериализовать обратно в список объектов java:

package com.derp.procedure.model;

import java.util.LinkedList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

import com.derp.generic.model.GenericDictionaryModel;

@Entity
@Table(name="procedure__Skeleton")
public class Skeleton extends GenericDictionaryModel<Skeleton> {

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private List<SkeletonElement> skeletonElements;

    public void setSkeletonElements(List<SkeletonElement> skeletonElements) {this.skeletonElements = skeletonElements;}
    public List<SkeletonElement> getSkeletonElements() {return skeletonElements;}
    public List<SkeletonElement> getSkeletonParentsElements() {
        List<SkeletonElement> skeletonParentsElements = new LinkedList<SkeletonElement>();
        for(int i=0; i<this.skeletonElements.size(); i++) {
            if(this.skeletonElements.get(i).getParent()==null) {
                skeletonParentsElements.add(this.getSkeletonElements().get(i));
            }
        }
        return skeletonParentsElements;
    }

    public Skeleton(String name) {
        super(name);
    }

    public Skeleton() {
        // TODO Auto-generated constructor stub
    }

    public String getSkeletonElementsJsonTree() {
        String jsonTreeString ="[";
        List<SkeletonElement> skeletonParentsElements = getSkeletonParentsElements();
        for(int i=0; i<skeletonParentsElements.size(); i++) {
            jsonTreeString = jsonTreeString + skeletonParentsElements.get(i).toJson();
            if((1+i) != skeletonParentsElements.size()) {
                jsonTreeString = jsonTreeString + ",";
            }
        }
        return jsonTreeString + "]";
    }
    public void setSkeletonElements(String skeletonElementsJson) {
        this.skeletonElements.get(0).toObject(skeletonElementsJson);
    }



}

И, по крайней мере, моя строка json, которую я хочу десериализовать:

[
    {
        "name": "Title1",
        "id": "1",
        "type": "SkeletonJobElement",
        "parent_id": "null",
        "children": [
            {
                "name": "Title11",
                "id": "2",
                "type": "SkeletonJobElement",
                "parent_id": "1",
                "children": [
                    {
                        "name": "Title111",
                        "id": "5",
                        "type": "SkeletonFileElement",
                        "parent_id": "2",
                        "children": []
                    },
                    {
                        "name": "Title112",
                        "id": "6",
                        "type": "SkeletonFileElement",
                        "parent_id": "2",
                        "children": []
                    }
                ]
            }
        ]
    },
    {
        "name": "Title2",
        "id": "3",
        "type": "SkeletonJobElement",
        "parent_id": "null",
        "children": [
            {
                "name": "Title21",
                "id": "4",
                "type": "SkeletonJobElement",
                "parent_id": "3",
                "children": []
            }
        ]
    }
]

Я знаю, что много кода для анализа, но, пожалуйста, помогите мне разобраться. Я так долго борюсь с ним на неделю.

Ответ 1

com.derp.procedure.model.SkeletonElement - абстрактный класс. Сделайте этот класс конкретным, удалив абстрактный модификатор.

Ответ 2

Если вы используете Kotlin, также измените класс abstract на класс open, решите проблему.

Ответ 3

Если вы хотите сохранить абстракцию класса, вам нужно написать собственную десериализацию с помощью Gson JsonDeserializer и зарегистрировать ее как адаптер типа. Допустим, у вас есть абстрактный класс A и производный класс B (B расширяет A):

JsonDeserializer<A> deserializer = ...; 
gsonBuilder.registerTypeAdapter(A.class, deserializer);

Теперь внутри JsonDeserializer вы должны указать, что A должен десериализоваться в B:

return context.deserialize(json, B.class);

Это имеет больше смысла, если у вас есть несколько классов, производных от абстрактного класса A Допустим, что и B и C происходят от A В этом сценарии вам потребуется обработать десериализацию для них обоих (внутри JsonDeserializer<A>):

if (json is of class B) {
  return context.deserialize(json, B.class);
}
if (json is of class C) {
  return context.deserialize(json, C.class);
}
...