【问题标题】:JAX-RS HATEOAS Using Jersey, Unwanted Link properties in JSONJAX-RS HATEOAS 使用 Jersey,JSON 中不需要的链接属性
【发布时间】:2014-09-18 01:24:53
【问题描述】:

从 Jersey 2.9 开始,可以通过声明性链接为超媒体驱动的 REST API 创建链接关系。

这段代码,例如:

@InjectLink(
    resource = ItemResource.class,
    style = Style.ABSOLUTE,
    bindings = @Binding(name = "id", value = "${instance.id}"),
    rel = "self"
)
@XmlJavaTypeAdapter(Link.JaxbAdapter.class)
@XmlElement(name="link")
Link self;

...理论上预计会产生这样的 JSON:

"link" : {
    "rel" : "self",
    "href" : "http://localhost/api/resource/1"
}

但是,Jersey 会生成不同的 JSON,其中包含许多我不需要的属性:

"link" : {
   "rel" : "self",
   "uri" : "http://localhost/api/resource/1",
   "type": null,
   "uriBuilder" : null
}

另请注意,它使用uri 而不是href。我查看了 Jersey 对 Link 对象的实现,发现了 JerseyLink

我想使用 Jersey 的声明式链接,而不是推出我自己的实现。我最终使用 Jackson 注释只是为了忽略其他 JerseyLink 属性。

@JsonIgnoreProperties({ "uriBuilder", "params", "type", "rels" })

是否有人使用声明式链接与 Jersey 并具有预期的 JSON 输出(例如,href 而不是 uri,没有额外的 Jersey 属性)而不必使用 JsonIgnoreProperties 或其他黑客?

谢谢。

编辑

我使用一种我认为是 hack 的方法解决了这个问题,但对我来说效果很好,并且不需要使用复杂的适配器。

我意识到我实际上可以公开一个不同的对象,而不是 Jersey 注入的链接。

我创建了一个名为 ResourceLink 的包装器对象:

public class ResourceLink {
  private String rel;
  private URI href;

  //getters and setters
}

然后在我的表示对象中我有一个 getter 方法:

public ResourceLink getLink() {
   ResourceLink link = new ResourceLink();
   link.setRel(self.getRel());
   link.setHref(self.getUri());

   return link;
}

所以我使用 Jersey 来注入链接,但在我的表示对象的 getter 方法中返回了一个不同的对象。这将是序列化为 JSON 的属性,而不是注入的链接对象,因为我没有为它创建 getter 方法。

【问题讨论】:

  • 也许这与您的 InjectLink 示例无关。 null 值是否也为其他响应对象序列化?你可以change this behaviour globally
  • 我的表示对象上的空属性未序列化。但是当我添加带有 Injectlink 注释的 Link 属性时,Link 对象(特别是 JerseyLink)的 null 属性会被序列化。

标签: java rest jersey jax-rs jersey-2.0


【解决方案1】:

调查

环境:Jersey 2.13(所有提供程序版本也是 2.13)。

无论您使用声明式链接还是程序式链接,序列化都不应有所不同。我选择了程序化,只是因为 我可以 :-)

测试类:

@XmlRootElement
public class TestClass {
    private javax.ws.rs.core.Link link;

    public void setLink(Link link) { this.link = link; }

    @XmlElement(name = "link")
    @XmlJavaTypeAdapter(Link.JaxbAdapter.class)
    public Link getLink() { return link; }
}

@Path("/links")
public class LinkResource {  
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getResponse() {
        URI uri = URI.create("https://stackoverflow.com/questions/24968448");
        Link link = Link.fromUri(uri).rel("stackoverflow").build();
        TestClass test = new TestClass();
        test.setLink(link);
        return Response.ok(test).build();
    }
}

@Test
public void testGetIt() {
    WebTarget baseTarget = target.path("links");
    String json = baseTarget.request().accept(
            MediaType.APPLICATION_JSON).get(String.class);
    System.out.println(json); 
}

不同 Provider 的结果(无需额外配置)

jersey-media-moxy

依赖

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-moxy</artifactId>
</dependency>

结果(奇怪)

{
    "link": "javax.ws.rs.core.Link$JaxbLink@cce17d1b"
}

jersey-media-json-jackson

依赖

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
</dependency>

结果(关闭,但 params 是什么?)

{
    "link": {
        "params": {
            "rel": "stackoverflow"
        },
        "href": "https://stackoverflow.com/questions/24968448"
    }
}

jackson-jaxrs-json-provider

依赖

<dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-json-provider</artifactId>
    <version>2.4.0</version>
</dependency>

结果(两个不同的结果,两个不同的 JSON 提供程序)

resourceConfig.register(JacksonJsonProvider.class);

{
    "link": {
        "uri": "https://stackoverflow.com/questions/24968448",
        "params": {
            "rel": "stackoverflow"
        },
        "type": null,
        "uriBuilder": {
            "absolute": true
        },
        "rels": ["stackoverflow"],
        "title": null,
        "rel": "stackoverflow"
    }
}

resourceConfig.register(JacksonJaxbJsonProvider.class);

{
    "link": {
        "params": {
            "rel": "stackoverflow"
        },
        "href": "https://stackoverflow.com/questions/24968448"
    }
}

我的结论

我们使用@XmlJavaTypeAdapter(Link.JaxbAdapter.class) 注释该字段。让我们看一下这个适配器的sn-p

public static class JaxbAdapter extends XmlAdapter<JaxbLink, Link> {...}

所以从Link,我们被编组到JaxbLink

public static class JaxbLink {

    private URI uri;
    private Map<QName, Object> params;
    ...
}

jersey-media-moxy

似乎是一个错误...请参阅下面的解决方案。

其他人

另外两个依赖jackson-module-jaxb-annotations 来处理使用 JAXB 注释的编组。 jersey-media-json-jackson 将自动注册所需的JaxbAnnotationModule。对于jackson-jaxrs-json-provider,使用JacksonJsonProvider 将不支持JAXB 注解(无需配置),使用JacksonJsonJaxbProvider 将为我们提供JAXB 注解支持。

所以如果我们 JAXB 注释支持,我们将被编组到JaxbLink,这将给出这个结果

{
    "link": {
        "params": {
            "rel": "stackoverflow"
        },
        "href": "https://stackoverflow.com/questions/24968448"
    }
}

我们可以通过所有不需要的属性获得结果的方法是1),使用jackson-jaxrs-json-providerJacksonJsonProvider2),创建ContextResolver 代表ObjectMapper,我们注册JaxbAnnotationModule。你似乎正在做其中之一。


解决方案

以上内容仍然没有让我们到达我们想要到达的地方(即没有params)。

对于jersey-media-json-jacksonjackson-jaxrs-json-provider...

...使用Jackson,此时我唯一能想到的就是创建一个自定义序列化程序

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import javax.ws.rs.core.Link;

public class LinkSerializer extends JsonSerializer<Link>{

    @Override
    public void serialize(Link link, JsonGenerator jg, SerializerProvider sp) 
            throws IOException, JsonProcessingException {
        jg.writeStartObject();
        jg.writeStringField("rel", link.getRel());
        jg.writeStringField("href", link.getUri().toString());
        jg.writeEndObject();
    }
}

然后为ObjectMapper创建一个ContextResolver,我们在其中注册序列化器

@Provider
public class ObjectMapperContextResolver 
                          implements ContextResolver<ObjectMapper> {

    private final ObjectMapper mapper;

    public ObjectMapperContextResolver() {
        mapper = new ObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Link.class, new LinkSerializer());
        mapper.registerModule(simpleModule);
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return mapper;
    }
}

这是结果

{
    "link": {
        "rel": "stackoverflow",
        "href": "https://stackoverflow.com/questions/24968448"
    }
}

使用 jersey-media-moxy,似乎有一个 Bug 缺少 JaxbLink 类中的设置器,因此编组恢复为调用 toString,如上所示。正如here by Garard Davidson 提议的那样,解决方法就是创建另一个适配器

import java.net.URI;
import java.util.HashMap;  
import java.util.Map;  

import javax.ws.rs.core.Link;  
import javax.xml.bind.annotation.XmlAnyAttribute;
import javax.xml.bind.annotation.XmlAttribute;

import javax.xml.bind.annotation.adapters.XmlAdapter;  
import javax.xml.namespace.QName;  

public class LinkAdapter  
    extends XmlAdapter<LinkJaxb, Link> {  

    public LinkAdapter() {  
    }  

    public Link unmarshal(LinkJaxb p1) {  

        Link.Builder builder = Link.fromUri(p1.getUri());  
        for (Map.Entry<QName, Object> entry : p1.getParams().entrySet()) {  
            builder.param(entry.getKey().getLocalPart(), entry.getValue().toString());  
        }  
        return builder.build();  
    }  

    public LinkJaxb marshal(Link p1) {  

        Map<QName, Object> params = new HashMap<>();  
        for (Map.Entry<String,String> entry : p1.getParams().entrySet()) {  
            params.put(new QName("", entry.getKey()), entry.getValue());  
        }  
        return new LinkJaxb(p1.getUri(), params);  
    }  
}  

class LinkJaxb  {  

    private URI uri;  
    private Map<QName, Object> params;  


    public LinkJaxb() {  
        this (null, null);  
    }  

    public LinkJaxb(URI uri) {  
        this(uri, null);  
    }  

    public LinkJaxb(URI uri, Map<QName, Object> map) {  

        this.uri = uri;  
        this.params = map!=null ? map : new HashMap<QName, Object>();  

    }  

    @XmlAttribute(name = "href")  
    public URI getUri() {   
        return uri;  
    }  

    @XmlAnyAttribute  
    public Map<QName, Object> getParams() {   
        return params;  
    }  

    public void setUri(URI uri) {  
        this.uri = uri;  
    }  

    public void setParams(Map<QName, Object> params) {  
        this.params = params;  
    }    
}

改用这个适配器

@XmlElement(name = "link")
@XmlJavaTypeAdapter(LinkAdapter.class)
private Link link;

会给我们想要的输出

{
    "link": {
        "href": "https://stackoverflow.com/questions/24968448",
        "rel": "stackoverflow"
    }
}

更新

现在我想起来了,LinkAdapter 也可以与 Jackson 提供者一起使用。无需创建 Jackson Serializer/Deserializer。假设启用了JacksonFeature,Jackson 模块应该已经支持 JAXB 注释。上面的示例分别显示了使用 JAXB/JSON 提供程序,但假设仅启用了 JacksonFeature,则应使用提供程序的 JAXB 版本。这实际上可能是更优选的解决方案。无需为ObjectMapper 创建ContextResolvers :-D

也可以在包级别声明注解,见here

【讨论】:

    【解决方案2】:

    我想与 Jackson 和 the mix-in annotations 分享我的序列化/反序列化 Link 对象的解决方案。

    LinkMixin:

    @JsonAutoDetect(
            fieldVisibility = JsonAutoDetect.Visibility.NONE,
            getterVisibility = JsonAutoDetect.Visibility.NONE,
            isGetterVisibility = JsonAutoDetect.Visibility.NONE)
    @JsonDeserialize(using = LinkMixin.LinkDeserializer.class)
    public abstract class LinkMixin extends Link {
    
        private static final String HREF = "href";
    
        @JsonProperty(HREF)
        @Override
        public abstract URI getUri();
    
        @JsonAnyGetter
        public abstract Map<String, String> getParams();
    
        public static class LinkDeserializer extends JsonDeserializer<Link> {
    
            @Override
            public Link deserialize(
                    final JsonParser p,
                    final DeserializationContext ctxt) throws IOException {
                final Map<String, String> params = p.readValueAs(
                        new TypeReference<Map<String, String>>() {});
                if (params == null) {
                    return null;
                }
                final String uri = params.remove(HREF);
                if (uri == null) {
                    return null;
                }
                final Builder builder = Link.fromUri(uri);
                params.forEach(builder::param);
                return builder.build();
            }
        }
    }
    

    例子:

    final ObjectMapper mapper = new ObjectMapper();
    mapper.addMixIn(Link.class, LinkMixin.class);
    final Link link = Link.fromUri("http://example.com")
            .rel("self")
            .title("xxx")
            .param("custom", "my")
            .build();
    final String json = mapper
            .writerWithDefaultPrettyPrinter()
            .writeValueAsString(Collections.singleton(link));
    System.out.println(json);
    final List<Link> o = mapper.readValue(json, new TypeReference<List<Link>>() {});
    System.out.println(o);
    

    输出:

    [ {
      "href" : "http://example.com",
      "rel" : "self",
      "title" : "xxx",
      "custom" : "my"
    } ]
    [<http://example.com>; rel="self"; title="xxx"; custom="my"]
    

    【讨论】:

      【解决方案3】:

      使用建议的更新解决方案,我仍然在 params 映射中获取 rel 部分。

      我对 Link 适配器类做了一些改动

      public class LinkAdapter
          extends XmlAdapter<LinkJaxb, Link> {
      
          public LinkAdapter() {
          }
      
          public Link unmarshal(LinkJaxb p1) {
      
              Link.Builder builder = Link.fromUri(p1.getUri());
      
              return builder.build();
          }
      
          public LinkJaxb marshal(Link p1) {
      
              return new LinkJaxb(p1.getUri(), p1.getRel());
          }
      }
      
      class LinkJaxb  {
      
          private URI uri;
          private String rel;
      
      
          public LinkJaxb() {
              this (null, null);
          }
      
          public LinkJaxb(URI uri) {
              this(uri, null);
          }
      
          public LinkJaxb(URI uri,String rel) {
      
              this.uri = uri;
              this.rel = rel;
      
          }
      
          @XmlAttribute(name = "href")
          public URI getUri() {
              return uri;
          }
          @XmlAttribute(name = "rel")
          public String getRel(){return rel;}
      
          public void setUri(URI uri) {
              this.uri = uri;
          }
      
      
      }
      

      它现在只包含需要的两个参数 (rel,href) 我真的不明白什么时候需要将 Jaxb 链接解组到链接。 对我来说重要的是链接到 Jaxb 链接编组。

      【讨论】:

        【解决方案4】:

        感谢@peeskillet 和@Nir Sivan 的回答。但我能够不使用使用LinkAdapterContextResolver&lt;ObjectMapper&gt; 使其工作。

        我刚刚将自定义链接类型的实例变量(此处为 ResourceLink,类似于您的 LinkJaxb)作为 @Transient 属性添加到我的实体类中,之后杰克逊配置自动将该属性包含在响应中JSON

        资源链接 - 类

        import javax.xml.bind.annotation.XmlAttribute;
        
        import com.fasterxml.jackson.annotation.JsonInclude;
        import com.fasterxml.jackson.annotation.JsonInclude.Include;
        
        @JsonInclude(Include.NON_EMPTY)
        public class ResourceLink  {
        
        private String uri;
        private String rel;
        
        
        public ResourceLink() {
            this (null, null);
        }
        
        public ResourceLink(String uri) {
            this(uri, null);
        }
        
        public ResourceLink(String uri,String rel) {
        
            this.uri = uri;
            this.rel = rel;
        
        }
        
        @XmlAttribute(name = "href")
        public String getUri() {
            return uri;
        }
        @XmlAttribute(name = "rel")
        public String getRel(){return rel;}
        
        public void setUri(String uri) {
            this.uri = uri;
        }
        
        
        }
        

        实体类

        package com.bts.entities;
        
        import java.util.ArrayList;
        import java.util.List;
        
        import javax.persistence.Column;
        import javax.persistence.Entity;
        import javax.persistence.GeneratedValue;
        import javax.persistence.Id;
        import javax.persistence.Table;
        import javax.persistence.Transient;
        
        import com.bts.rs.root.util.ResourceLink;
        import com.fasterxml.jackson.annotation.JsonInclude;
        import com.fasterxml.jackson.annotation.JsonInclude.Include;
        
        @Entity
        @Table(name="cities")
        @JsonInclude(Include.NON_EMPTY)
        public class City {
            @Id
            @Column(name="city_id")
            private Integer cityId;
        
            @Column(name="name")
            private String name;
        
            @Column(name="status")
            private int status;
        
            @Column(name="del_status")
            private int delStatus;
        
            @Transient
            List<ResourceLink> links = new ArrayList<ResourceLink>();
        
            // private 
            public City () {
        
            }
        
            public City (Integer id, String name) {
                this.cityId = id;
                this.name = name;
                this.status = 0;
                this.delStatus = 0;
            }
        
            // getters and setters for Non-transient properties
        
            // Below is the getter for lInks transient attribute
            public List<ResourceLink> getLinks(){
                return this.links;
            }
        
            // a method to add links - need not be a setter necessarily
            public void addResourceLink (String uri,String rel) {
                this.links.add(new ResourceLink(uri, rel));
            }   
        }
        

        Jersy 资源提供者

        @GET
        @Path("/karanchadha")
        @Produces({MediaType.APPLICATION_JSON})
        @Transactional
        public Response savePayment() {
            City c1 = new City();
            c1.setCityId(11);
            c1.setName("Jamshedpur");
            c1.addResourceLink("http://www.test.com/home", "self");
            c1.addResourceLink("http://www.test.com/2", "parent");
        
            return Response.status(201).entity(c1).build();
        }
        

        【讨论】:

        • 嗨,Karan,我不太明白你在这里做什么。您有 GET 假定这是在读取,但该方法称为 savePayment() 这意味着您正在保存。如果是保存,那么临时链接就不会存入数据库,下次需要读取实体时如何生成这些链接呢?如果您正在保存,那么这些 URL 是从哪里来的?
        【解决方案5】:

        第一个依赖项:

        <dependency> 
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-jackson</artifactId> 
            <version>2.34</version>
        </dependency> 
        <dependency>
            <groupId>org.glassfish.jersey.ext</groupId>
            <artifactId>jersey-declarative-linking</artifactId>
            <version>2.34</version>
        </dependency>
        

        第二个 - 配置类:

        package app.rest.config;
        
        import javax.ws.rs.ApplicationPath;
        import org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJaxbJsonProvider;
        import org.glassfish.jersey.linking.DeclarativeLinkingFeature;
        import org.glassfish.jersey.server.ResourceConfig;
        
        
        @ApplicationPath(value = "rest")
        public class RestApplicationConfig extends ResourceConfig{
        
            public RestApplicationConfig() {
                register(JacksonJaxbJsonProvider.class);
                register(DeclarativeLinkingFeature.class);
                packages("app.rest.controllers");
            }
        
        
        }
        

        第三 - 创建适配器类

        package app.rest.config;
        
        import javax.json.Json;
        import javax.json.JsonObject;
        import javax.json.bind.adapter.JsonbAdapter;
        import javax.ws.rs.core.Link;
        import javax.ws.rs.core.UriBuilder;
        
        
        public class CustomJsonAdapter implements JsonbAdapter<Link, JsonObject> {
        
            @Override
            public JsonObject adaptToJson(Link link) throws Exception {
                StringBuilder builder = new StringBuilder();
                builder.append("http://");
                builder.append(link.getUri().getHost());
                builder.append(":");
                builder.append(link.getUri().getPort());
                builder.append(link.getUri().getRawPath());
                return Json.createObjectBuilder().add("href", builder.toString()).add("rel", link.getRel()).build();
            }
        
            @Override
            public Link adaptFromJson(JsonObject json) throws Exception {
                Link link = Link.fromUriBuilder(UriBuilder.fromUri(json.getString("href"))).rel(json.getString("rel")).build();
                return link;
            }
        
        }
        

        Forth - 使用从 Link 类到 Json 的自定义适配器类注册 JsonbConfig

        package app.rest.config;
        
        import javax.json.bind.Jsonb;
        import javax.json.bind.JsonbBuilder;
        import javax.json.bind.JsonbConfig;
        import javax.ws.rs.ext.ContextResolver;
        import javax.ws.rs.ext.Provider;
        
        @Provider
        public class AppJsonConfig implements ContextResolver<Jsonb>  {
        
            @Override
            public Jsonb getContext(Class<?> type) {
                JsonbConfig jsonbConfig = new JsonbConfig();
                jsonbConfig.withAdapters(new CustomJsonAdapter());
                return JsonbBuilder.create(jsonbConfig);
            }
        
        }
        

        第五:创建带有Link和@InjectLink注解的模型

        package app.rest.model;
        
        import java.io.Serializable;
        import java.util.Objects;
        import javax.json.bind.annotation.JsonbTypeAdapter;
        import javax.ws.rs.core.Link;
        import javax.xml.bind.annotation.XmlRootElement;
        import org.glassfish.jersey.linking.Binding;
        import org.glassfish.jersey.linking.InjectLink;
        import org.glassfish.jersey.linking.InjectLink.Style;
        import app.rest.config.CustomJsonAdapter;
        import app.rest.controllers.RestController;
        
        
        @XmlRootElement
        public class StudentResource implements Serializable{
        
            private static final long serialVersionUID = 1L;
        
            private Long id;
        
            private String name;
        
            private String surname;
        
            @InjectLink(resource = RestController.class, 
                        style = Style.ABSOLUTE,
                        rel = "self", 
                        method = "getStudentById",
                        bindings = @Binding(name = "id", value = "${instance.id}"))
            @JsonbTypeAdapter(value = CustomJsonAdapter.class)
            private Link link;
        
            public String getName() {
                return name;
            }
            public void setName(String name) {
                this.name = name;
            }
            public String getSurname() {
                return surname;
            }
            public void setSurname(String surname) {
                this.surname = surname;
            }
        
            public Long getId() {
                return id;
            }
            public void setId(Long id) {
                this.id = id;
            }
        
            public Link getLink() {
                return link;
            } 
            public void setLink(Link link) {
                this.link = link;
            }
            @Override
            public int hashCode() {
                return Objects.hash(name, surname);
            }
            @Override
            public boolean equals(Object obj) {
                if (this == obj)
                    return true;
                if (obj == null)
                    return false;
                if (getClass() != obj.getClass())
                    return false;
                StudentResource other = (StudentResource) obj;
                return Objects.equals(name, other.name) && Objects.equals(surname, other.surname);
            }
        }
        

        最后是休息控制器

        package app.rest.controllers;
        
        import java.net.URISyntaxException;
        import java.util.ArrayList;
        import java.util.Iterator;
        import java.util.List;
        import javax.ws.rs.GET;
        import javax.ws.rs.Path;
        import javax.ws.rs.PathParam;
        import javax.ws.rs.Produces;
        import javax.ws.rs.core.Context;
        import javax.ws.rs.core.GenericEntity;
        import javax.ws.rs.core.Link;
        import javax.ws.rs.core.MediaType;
        import javax.ws.rs.core.Response;
        import javax.ws.rs.core.UriInfo;
        import app.rest.model.*;
        
        @Path(value = "student")
        public class RestController {
        
            @Context
            private UriInfo uriInfo;
        
            private final ArrayList<StudentResource> students = new ArrayList<>();
        
            public RestController() {
                StudentResource s1 = new StudentResource();
                s1.setId(1L);
                s1.setName("test1");
                s1.setSurname("surTest1");
                students.add(s1);
                StudentResource s2 = new StudentResource();
                s2.setId(2L);
                s2.setName("new_St");
                s2.setSurname("surNew");
                students.add(s2);
            
            }
        
            @GET
            @Produces(MediaType.APPLICATION_JSON)
            public Response  getAllStudents() throws URISyntaxException{
                Link link = Link.fromUriBuilder(uriInfo.getAbsolutePathBuilder()).rel("self").type("GET").build();
                GenericEntity<List<StudentResource>> studentsEntities = new GenericEntity<List<StudentResource>>(students) {};
                return Response.status(Response.Status.OK).entity(studentsEntities).links(link).build();
            }
        
            @GET
            @Path(value = "/{id}")
            @Produces(MediaType.APPLICATION_JSON)
            public Response getStudentById(@PathParam(value = "id") Long id ) {
                Iterator<StudentResource> iterator = students.iterator();
                StudentResource studentById= null;
                while (iterator.hasNext()) {
                    StudentResource next = iterator.next();
                    if(next.getId().equals(id)) {
                        studentById = next;
                        break;
                    }
                }
                if(null!=studentById) return Response.status(Response.Status.OK).entity(studentById).build();
            
                else return Response.status(Response.Status.NO_CONTENT).build();
            }   
        
        }
        

        在 Payara 5.201 上部署和测试

        生成:获取 http://localhost:8080/sampleappee/rest/student/1

        {"id":1,"link":{"href":"http://localhost:8080/sampleappee/rest/student/1","rel":"self"},"name":"test1","surname":"surTest1"}
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-06-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-09-25
          • 2016-04-13
          • 2011-10-26
          相关资源
          最近更新 更多