【问题标题】:GET request fails with JAX-RS: Could not find MessageBodyWriter for response object of type: java.util.ArrayList of media type: text/htmlGET 请求因 JAX-RS 失败:找不到 MessageBodyWriter 类型的响应对象:媒体类型的 java.util.ArrayList:text/html
【发布时间】:2017-05-07 15:23:46
【问题描述】:

我正在使用 JEE7 使用 JAX-RS 构建示例客户端服务器。我正在使用 Wildfly 10.1

我在this 视频中关注了那个人。以下是在应用服务器上运行的战争代码:

boundary 包包含服务

package pl.devcrowd.virtual.business.chickens.boundary;

import java.util.List;

import javax.ejb.Stateless;
import javax.inject.Inject;

import pl.devcrowd.virtual.business.chickens.controls.ChickenStore;
import pl.devcrowd.virtual.business.chickens.entity.Chicken;

@Stateless
public class ChickenService {

    @Inject
    ChickenStore cs;

    public List<Chicken> getAllChickens() {
        return this.cs.all();
    }

    public void save(Chicken chicken) {
        this.cs.save(chicken);
    }
}

和资源

package pl.devcrowd.virtual.business.chickens.boundary;

import java.util.List;

import javax.inject.Inject;
import javax.json.JsonObject;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;

import pl.devcrowd.virtual.business.chickens.entity.Chicken;

@Path("chickens")
public class ChickensResource {

    @Inject
    ChickenService cs;

    @GET
    public List<Chicken> chickens() {
        return cs.getAllChickens();
    }

    @POST
    public void save(JsonObject chicken) {
        String name = chicken.getString("name");
        int age = chicken.getInt("age");
        cs.save(new Chicken(name, age));
    }
}

control 包中包含在这个例子中大部分没用的商店

package pl.devcrowd.virtual.business.chickens.controls;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import pl.devcrowd.virtual.business.chickens.entity.Chicken;

public class ChickenStore {

    @PersistenceContext
    EntityManager em;

    public void save(Chicken chicken) {
        em.merge(chicken);
    }

    public List<Chicken> all() {
        return this.em
                .createNamedQuery("all", Chicken.class)
                .getResultList();
    }
}

entity 包中包含实体:

package pl.devcrowd.virtual.business.chickens.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
@Entity
@NamedQuery(name="all", query = "SELECT c FROM Chicken C")
public class Chicken {

    @Id
    @GeneratedValue
    private long id;
    private String name;
    private int age;

    public Chicken() {}

    public Chicken(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

父包包含我实现的Jax-RS应用类,希望是正确的:

package pl.devcrowd.virtual.business;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

import pl.devcrowd.virtual.business.chickens.boundary.ChickensResource;

/**
 * Configures a JAX-RS endpoint. Delete this class, if you are not exposing
 * JAX-RS resources in your application.
 *
 * @author airhacks.com
 */
@ApplicationPath("resources")
public class JAXRSConfiguration extends Application {
    public Set<Class<?>> getClasses() {
        return new HashSet<Class<?>>(Arrays.asList(ChickensResource.class));
    }
}

现在我正在尝试执行这样的 GET 请求

RestClient get = RestClient.create().method("GET")
        .host("http://localhost:8080/DevCrowd")
        .path("resources/chickens");
GluonObservableList<Chicken> sample = DataProvider.retrieveList(
        get.createListDataReader(Chicken.class));
System.out.println(sample);

鸡在哪里

public class Chicken {

    private String name;
    private int age;

    public Chicken(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

我得到了错误:

05:59:17,019 ERROR [org.jboss.resteasy.resteasy_jaxrs.i18n] (default task-3) RESTEASY002005: Failed executing GET /chickens: org.jboss.resteasy.core.NoMessageBodyWriterFoundFailure: Could not find MessageBodyWriter for response object of type: java.util.ArrayList of media type: text/html
    at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:66)
    at org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:473)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:422)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:209)
    at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:221)
    at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
    at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
    at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85)
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
    at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
    at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
    at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
    at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
    at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
    at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
    at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
    at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
    at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
    at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
    at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
    at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
    at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
    at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
    at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:202)
    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:805)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

我做错了什么?

【问题讨论】:

    标签: java jakarta-ee jax-rs gluon-mobile


    【解决方案1】:

    据我所知,客户要求媒体类型 text/html。但是objectmapper 不知道如何为arraylist 编写html。 你期待xml还是json是什么格式?

    @Path("chickens")
    public class ChickensResource {
    
        @Inject
        ChickenService cs;
    
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        public List<Chicken> chickens() {
            return cs.getAllChickens();
        }
    
        @POST
        @Consumes(MediaType.APPLICATION_JSON)
        @Produces(MediaType.APPLICATION_JSON)
        public void save(JsonObject chicken) {
            String name = chicken.getString("name");
            int age = chicken.getInt("age");
            cs.save(new Chicken(name, age));
        }
    }
    

    另一种解决方案是在请求中设置正确的请求内容类型: 获取标题:

     Accept: application/json
    

    POST 标题:

    Accept: application/json
    Content-Type: application/json
    

    Accept 标头说明响应应该采用哪种格式。 Content-Type 标头说明了请求有效负载的格式。

    内容类型:

    HTML --> text/html
    JSON --> application/json
    XML --> application/xml
    

    编辑:我认为 Post 也有同样的问题。我们现在告诉方法,它们使用 json 作为输入数据并返回 json 作为输出数据(生产)。

    但是这些数据真的是在请求中设置的吗?能否请您发布您如何构建帖子。

    要匹配这些方法,请求中需要有这两个标头: Accept: application/json 表示客户期望的格式。 这应该与设置输出格式的服务中的@Produces 匹配。 Content-Type: application/json 这是我认为缺少的那个说 POST 有效负载的格式,这应该与服务器输入 @Consumes

    【讨论】:

    • 我添加了@Consumes@Produces。 GET 现在可以工作,我应该得到一个空列表[]!谢谢!现在我对 POST 有疑问:Failed to execute: javax.ws.rs.NotSupportedException: RESTEASY003065: Cannot consume content type。我可以问一个关于 POST 的新问题,因为这个问题是关于让 GET 工作的,但是你知道问题出在哪里吗?客户端还是服务器?我理解错误的含义,而不是为什么会发生或如何解决它。
    猜你喜欢
    • 1970-01-01
    • 2013-11-02
    • 2013-04-16
    • 2012-08-21
    • 2013-10-06
    • 2013-03-15
    • 2020-07-30
    • 2017-06-05
    • 2017-01-11
    相关资源
    最近更新 更多