JAX-RS (Дженсон + Джерси): объект не преобразован в json - PullRequest
0 голосов
/ 09 октября 2018

У меня есть пример rest приложения, которое работает на tomcat.

При ответе - объект типа ActionError отправляется клиенту в виде строки json.

ActionError передаст клиенту

  1. Array из Strings 2
  2. Array из FieldError s
  3. Произвольный Object полезная нагрузка (определяется как универсальный тип).

В моем тесте я передаю в качестве payload объект типа Employee.

При вышеуказанном расположении - все работает нормально.И я получаю результаты, такие как:

{"actionErrors":["everything is ok"],"fieldErrors":null,"payload":{"empName":"Jony","empNo":"E3","position":"Manager"}}

Однако , если я удаляю Array из FieldError (private ArrayList<FieldError> fieldErrors;), поэтому -что ActionError теперь содержит только:

1. Array из Strings

2. Object payload

, как ни странно, payload неправильно сериализовано и я получаю:

{"actionErrors":["everything is ok"],"payload":"com.mycompany.mavenwebproject.model.Employee@41a8e0d9"}

Что не может быть причиной этого?Любые идеи о том, как это можно исправить?

Спасибо.

Ниже приведены определения классов:

ActionError.java

@XmlRootElement(name = "actionError")
@XmlAccessorType(XmlAccessType.FIELD)
public class ActionError<T> {
   private ArrayList<String> actionErrors;
   private ArrayList<FieldError> fieldErrors;
   private T payload;

    /**
     * @return the actionErrors
     */
    public ArrayList<String> getActionErrors() {
        return actionErrors;
    }

    /**
     * @param actionErrors the actionErrors to set
     */
    public void setActionErrors(ArrayList<String> actionErrors) {
        this.actionErrors = actionErrors;
    }

    /**
     * @return the fieldErrors
     */
    public ArrayList<FieldError> getFieldErrors() {
        return fieldErrors;
    }

    /**
     * @param fieldErrors the fieldErrors to set
     */
    public void setFieldErrors(ArrayList<FieldError> fieldErrors) {
        this.fieldErrors = fieldErrors;
    }

    public void addFieldError(String fieldName,String errorMessage){
         if (this.fieldErrors==null)
             this.fieldErrors = new ArrayList<>();
         this.fieldErrors.add(new FieldError(fieldName, errorMessage));
    }

    public void addActionError(String errorMessage){
         if (this.actionErrors==null)
             this.actionErrors = new ArrayList<>();
         this.actionErrors.add(errorMessage);
    }

    public boolean hasErrors(){
      return (fieldErrors!=null && !fieldErrors.isEmpty()) || (actionErrors!=null && !actionErrors.isEmpty());
    }

    /**
     * @return the payload
     */
    public T getPayload() {
        return payload;
    }

    /**
     * @param payload the payload to set
     * @return 
     */
    public ActionError setPayload(T payload) { //Class<T> payloadClass
        this.payload = payload;
        return this;
    }
}

FieldError.java

@XmlRootElement(name = "fieldError")
@XmlAccessorType(XmlAccessType.FIELD)
public class FieldError {
    private String fieldName;
    private String fieldError;

    /**
     * @return the fieldName
     */
    public String getFieldName() {
        return fieldName;
    }

    /**
     * @param fieldName the fieldName to set
     */
    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }

    /**
     * @return the fieldError
     */
    public String getFieldError() {
        return fieldError;
    }

    /**
     * @param fieldError the fieldError to set
     */
    public void setFieldError(String fieldError) {
        this.fieldError = fieldError;
    }

    public FieldError(String fieldName, String fieldError) {
        this.fieldName = fieldName;
        this.fieldError = fieldError;
    }


}

Employee.java

@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee {

    private String empNo;
    private String empName;
    private String position;

    // This default constructor is required if there are other constructors.
    public Employee() {

    }

    public Employee(String empNo, String empName, String position) {
        this.empNo = empNo;
        this.empName = empName;
        this.position = position;
    }

    public String getEmpNo() {
        return empNo;
    }

    public void setEmpNo(String empNo) {
        this.empNo = empNo;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

}

1 Ответ

0 голосов
/ 12 октября 2018

Мне удалось запустить вышеописанное на Glassfish 4.1.1 и Tomcat 8, используя следующие зависимости:

Tomcat 8

<dependency>
    <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.bundles/jaxrs-ri -->
        <groupId>org.glassfish.jersey.bundles</groupId>
        <artifactId>jaxrs-ri</artifactId>
        <version>2.12</version>
        <type>zip</type>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.owlike/genson -->
    <dependency>
        <groupId>com.owlike</groupId>
        <artifactId>genson</artifactId>
        <version>1.4</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.2.7</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.ws.rs/javax.ws.rs-api -->
    <dependency>
        <groupId>javax.ws.rs</groupId>
        <artifactId>javax.ws.rs-api</artifactId>
        <version>2.0.1</version>
    </dependency>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-web-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency>

Glassfish 4.1.1

 <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>
  <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.bundles/jaxrs-ri -->      

        <dependency>
            <groupId>org.glassfish.jersey.bundles</groupId>
            <artifactId>jaxrs-ri</artifactId>
            <version>2.12</version>    
            <scope>provided</scope>
            <type>zip</type>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.owlike/genson -->

         <dependency>
            <groupId>com.owlike</groupId>
            <artifactId>genson</artifactId>
            <version>1.4</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.2.7</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.ws.rs/javax.ws.rs-api -->
        <dependency>
            <groupId>javax.ws.rs</groupId>
            <artifactId>javax.ws.rs-api</artifactId>
            <version>2.0.1</version>
        </dependency>
       <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>

Также мой web.xml имеет следующие записи:

<servlet>
        <servlet-name>jersey-serlvet</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
             <param-name>jersey.config.server.provider.packages</param-name>
             <param-value>com.mycompany.mavenwebproject</param-value>
        </init-param>
        <init-param>
        <param-name>jersey.config.server.provider.classnames</param-name>
        <param-value>org.glassfish.jersey.jackson.JacksonFeature</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>jersey-serlvet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

Также для запуска на Glassfish 3.1.2 Джерси 1.x должен быть использован, и Генсон не нужен.

Итак, зависимости pom.xml выглядят так:

<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-server</artifactId>
    <version>1.8</version>
</dependency>

<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-json</artifactId>
    <version>1.8</version>
</dependency>

   <dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-web-api</artifactId>
    <version>6.0</version>
    <scope>provided</scope>
</dependency>

и запись web.xml :

<servlet>
        <servlet-name>jersey-serlvet</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>com.mycompany.mavenwebproject</param-value>
        </init-param>
        <init-param>
            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>jersey-serlvet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

Редактировать 1

Чтобы отказаться от использования genson в glassfish 4.1.1, в каталог модулей Glassfish следует добавить отсутствующую библиотеку jackson-module-jaxb-annotations-2.5.4.jar.В противном случае

java.lang.ClassNotFoundException:
com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector не найден com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider

будет брошено.Но если добавить вышеупомянутую банку, пометка для Glassfish может быть следующей:

Glassfish 4.1.1 (исправлена ​​ошибка с отсутствующей библиотекой)

<dependencies>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.3.2</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>
  <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.bundles/jaxrs-ri -->      

        <dependency>
            <groupId>org.glassfish.jersey.bundles</groupId>
            <artifactId>jaxrs-ri</artifactId>
            <version>2.12</version>    
            <scope>provided</scope>
            <type>zip</type>
        </dependency>


        <!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.2.7</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.ws.rs/javax.ws.rs-api -->
        <dependency>
            <groupId>javax.ws.rs</groupId>
            <artifactId>javax.ws.rs-api</artifactId>
            <version>2.0.1</version>
        </dependency>

        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

Редактировать 2.

Если кто-то хочет использовать Джексона 2 на Glassfish 3.1.2 с трикотажем 1, то следующая конфигурация в следующем порядке

pom.xml

  <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>
  <dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-server</artifactId>
    <version>1.8</version>
</dependency>

<!-- removed to use jackson 2 not 1
<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-json</artifactId>
    <version>1.8</version>
</dependency>
-->

<!-- jackson 2 json provider  -->
<dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-json-provider</artifactId>
    <version>2.2.3</version>
</dependency>

<!-- jackson 2 xml provider 
<dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-xml-provider</artifactId>
    <version>2.2.3</version>
</dependency>
-->
<dependency>
    <groupId>com.sun.jersey.contribs</groupId>
    <artifactId>jersey-multipart</artifactId>
    <version>1.8</version>
</dependency>
   <dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-web-api</artifactId>
    <version>6.0</version>
    <scope>provided</scope>
    </dependency>
      <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.3.2</version> <!-- unlike jersey 2 on glassfish 4.1.1 here it is not provided! -->
       </dependency>

    </dependencies>

и web.xml становится

<servlet>
        <servlet-name>jersey-serlvet</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>
                                     com.mycompany.mavenwebproject
                                    <!--
                                    Jackson 2.x JAX-RS @Providers
                                    -->
                                     com.fasterxml.jackson.jaxrs.json <!--JSON -->
                                     <!-- com.fasterxml.jackson.jaxrs.xml  -->  <!-- XML -->
                        </param-value>
        </init-param>
        <init-param>
            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>jersey-serlvet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
...