我有一些使用JAX-RS和Jackson的REST服務。我的客戶希望抽象類作爲服務的返回類型,我不知道如何讓JAX-RS客戶端返回具體子類的實例。這是可能的XML和JSON表示?如果是這樣,將欣賞樣本和/或鏈接。JAX-RS:從聲明抽象返回類型的方法返回具體類實例
回答
有幾種方法可以實現這一點。最簡單的方法是使用@JsonTypeInfo
,as Garry mentioned。你所要做的就是用@JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY)
註釋你的抽象基類,你應該很好走。
另一種方法是確保服務器端和客戶端上的所有映射器都啓用(可能爲NON_FINAL)default typing,以便在未註釋的類上對(類型)信息進行序列化。如果您對開箱即用的序列化功能不滿意,可以通過提供自己的TypeResolverBuilder來加強這兩種方式。這些方法的更詳細的解釋可以在in this article或Jackson's Polymorphic Type Handling wiki page找到。
儘管@JsonTypeInfo
的方式很簡單,但實際上獲得CXF服務器/客戶端可能是一件苦差事。所以這裏有一個完整的例子:
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import com.fasterxml.jackson.jaxrs.xml.JacksonJaxbXMLProvider;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static javax.ws.rs.core.MediaType.APPLICATION_XML;
public class FullCxfJaxrsJacksonExample {
public static void main(String[] args) {
String serverAddress = "http://localhost:9000/";
Server server = null;
try {
// make server that supports JSON and XML
JAXRSServerFactoryBean serverFactory = new JAXRSServerFactoryBean();
serverFactory.setResourceClasses(ShapeServiceRandom.class);
serverFactory.setAddress(serverAddress);
serverFactory.setProviders(Arrays.asList(new JacksonJaxbJsonProvider(), new JacksonJaxbXMLProvider()));
server = serverFactory.create();
// make and use a client
JAXRSClientFactoryBean clientFactory = new JAXRSClientFactoryBean();
clientFactory.setAddress(serverAddress);
clientFactory.setServiceClass(ShapeService.class);
clientFactory.setProvider(new JacksonJaxbJsonProvider());
clientFactory.setHeaders(Collections.singletonMap("Accept", "application/json"));
// for an XML client instead of a JSON client, use the following provider/headers instead:
//clientFactory.setProvider(new JacksonJaxbXMLProvider());
//clientFactory.setHeaders(Collections.singletonMap("Accept", "application/xml"));
ShapeService shapeServiceClient = clientFactory.create(ShapeService.class);
for (int i = 0; i < 10; i++) {
System.out.format("created shape: %s\n", shapeServiceClient.create());
}
} finally {
if (server != null) {
server.destroy();
}
}
System.exit(0);
}
// Put JsonTypeInfo on the abstract base class so class info gets marshalled.
// You'll want CLASS instead of MINIMAL_CLASS if your base class and subclasses are in different packages.
@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, include = JsonTypeInfo.As.PROPERTY)
public abstract static class Shape {
}
public static class Circle extends Shape {
public double radius;
@Override
public String toString() {
return "Circle{radius=" + radius + '}';
}
}
public static class Polygon extends Shape {
public int numSides;
@Override
public String toString() {
return "Polygon{numSides=" + numSides + '}';
}
}
// service definition with abstract return type
@Path("/shape")
public interface ShapeService {
@GET
@Path("/create")
@Produces({APPLICATION_JSON, APPLICATION_XML})
Shape create();
}
// service implementation that returns different concrete subclasses
public static class ShapeServiceRandom implements ShapeService {
Random random = new Random();
public Shape create() {
int num = random.nextInt(8);
if (num > 3) {
Polygon polygon = new Polygon();
polygon.numSides = num;
return polygon;
} else {
Circle circle = new Circle();
circle.radius = num + 0.5;
return circle;
}
}
}
}
這個例子使用的是JDK 1.8.0_45成功進行了測試和下面的依賴關係:
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.5.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-xml-provider</artifactId>
<version>2.5.4</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
<version>3.1.1</version>
</dependency>
謝謝你的時間 –
很高興看到完整的代碼:) – Garry
你可以嘗試添加JsonTypeInfo和JsonSubTypes註釋
@JsonTypeInfo(use = Id.CLASS,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@Type(value = MySubClass.class)
})
public abstract class MyAbsClass {
....
}
public class MySubClass extends MyAbsClass {
....
}
它應該增加的類型信息,以JSON輸出。
如果您只想返回一個任意具體實例,那麼在使用基於Jackson的提供程序時,這個「正常工作」。這是JSON的默認值DropWizard
。可能發生的唯一問題是使用plain Jersey和基於JAXB的提供程序,這可能會限制序列化爲抽象類型公開的API。
如果您還需要能夠將客戶端反序列化爲具體類型,則需要使用@JsonTypeInfo
。
- 1. 覆蓋抽象方法的返回類型與具體類型
- 2. 從抽象父類中的方法返回具體子類的實例
- 3. 如何讓抽象方法返回具體實現的抽象類型?
- 4. 返回類的實例的抽象方法
- 5. 方法聲明的返回類型應該是接口還是具體類?
- 6. 返回派生類實例的抽象方法
- 7. 如何編寫一個返回抽象類實例的方法?
- 8. 返回NSMutableArray而不是聲明NSArray的Objective-c返回方法返回類型
- 9. Java中的所有抽象方法是用void返回類型聲明的嗎?
- 10. 實現抽象方法與返回類型的自我
- 11. 抽象類中的方法返回實現它的類的實例
- 12. 返回類和抽象類?
- 13. 如何指定抽象類的方法的返回類型
- 14. 在基類中返回抽象類型
- 15. 實現抽象方法返回類型<T1<T2>>
- 16. C++類方法聲明返回錯誤
- 17. 從抽象特質方法中返回相同的類型
- 18. Java泛型 - 覆蓋抽象方法並具有子類的返回類型
- 19. Scala抽象類/特徵與返回子類型的方法
- 20. 如何指定的抽象方法的返回類型爲實現類型
- 21. 從方法返回部分linq查詢 - 如何聲明返回類型
- 22. 返回具體或抽象數據類型?
- 23. 以抽象類作爲參數的Java方法返回子類的實例
- 24. 回報(類型)實例或返回實例作爲類型
- 25. 抽象類方法聲明
- 26. 返回子類實例的父方法
- 27. 的Java返回類型和抽象
- 28. 抽象與不同的返回類型
- 29. 閉幕聲明的返回類型
- 30. 如何從基類型中聲明的方法返回派生類型
也許@XmlSeeAlso使用JAXB? – nachokk
我寫了一個測試程序。 @XmlSeeAlso工作。 JSON怎麼樣? –
如果您在教程中使用球衣,說jaxb適用於json和xml .. – nachokk