I am working on creating a RESTful API for a project. I am facing a few problems trying to implement it with jersey:
My object model does not contain uri info obviously. e.g, lets say I have a Fruit class. Fruit object would have let's say a FruitName and a FruitColor. But in the response I also need to send a URI. How is this usually handled? Should I create a separate "FruitResource" that has a constructor which takes a "Fruit" and creates a full resource from it, including URI? I need URIs in the nested objects as well, e.g if I am returning a list of Child objects, I need each Child object to also have a URI, but I donlt want the URI to be part of the object model. What is the cleanest way to do this?
I want to have capability to return full and partial views of the same resource. Partial views would just have the name and the URI for example. How to get this done?
Right now what I have is a Service class that accepts the requests, which uses the DAO to create and return the objects as they are modelled from the DB, serialized to JSON using jackson.
There i a way to use JaxB class and you can pass Object Model to JaxB class and JaxB class generates URI.
The below is small prototype.
UserResource Class
#Path("/user")
public class UserResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("{user-id}")
public UserJaxB getUser(#PathParam("user-id") String userId, #Context
HttpServletRequest request) {
// now XYZ is hard-coded value
String serviceEndpoint = request.getContextPath() + "/" + "user";
UserModel userModel = new UserModel(userId, "XYZ");
return new UserJaxB(serviceEndpoint,userModel);
}
}
User JAXB Class
#XmlRootElement
public class UserJaxB {
private String name;
private String id;
private String serviceEndpoint;
private String URI;
public UserJaxB(String serviceEndpoint, UserModel userModel) {
this.name = userModel.getName();
this.id = userModel.getId();
this.serviceEndpoint = serviceEndpoint;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getURI() {
return this.serviceEndpoint + "/" + id;
}
}
User Model Class
public class UserModel {
String name;
String id;
public UserModel(String name, String id) {
this.name = name;
this.id = id;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
}
I'm working on a project that supports both of those concerns: https://github.com/skyscreamer/yoga with more information at http://yoga.skyscreamer.org/, including a demo.
It replaces the JAX-RS (or Spring MVC) rendering mechanism with a custom built solution that's more in tune with the needs of a REST System.
For #1, we have an annotation that you have to apply to your Child pojo. JAX-RS's annotations are meant to map URLs to controllers not to the underlying object, so we needed a custom solution... but it's really just comes down to 1 additional annotation per pojo.
For #2, we have a URL based mechanism of specifying which additional information you want from a pojo or a pojo's children (and can be nested further).
I hope this helps.
1) I'm not aware of any Jersey or JAX-RS mechanism supporting this. Seems like a bad practice to have to add the URI to the constructor for each of your domain classes, though. You could create an aspect that would intercept the method and wrap the response in a new object - adding the URI of the resource in the wrapper (you could get the URIInfo via reflection from the interceptor). I've done this when building etag support so I don't have to add cache code to every response. I suppose you could also add something in the same aspect to handle the child URI issue...
You might also want have a look at these dicussions:
http://java.net/projects/jersey/lists/users/archive/2009-01/message/357
http://markmail.org/search/?q=list%3Anet.java.dev.jersey.users+brett.dargan%40gmail.com#query:list%3Anet.java.dev.jersey.users%20brett.dargan%40gmail.com+page:1+mid:7ln7wixfihfodngg+state:results
2) For building "lighter" response entities I typically have a BeanLite.class with just the properties I need for a summary and then a Bean.class extending it with more detail. You can add both to your ORM and provide an option to switch representations in your DAO.
Thanks for all your responses. Going through all the approaches you guys presented and after a little bit of research on my own, this is what I settled on:
1) I am adding uri as part of the object model. This seems to be the cleanest solution to me currently. The URI can be automatically populated whenever the object is created (using other properties of the object). Earlier I thought this is a bad idea, but I am not able to foresee any problems with this approach other than the extra field that will have to keep moving with the objects.
2) For supporting full/partial views, I am trying to use the #JsonView annotation. This seems to be a good approach.
Let me know if there are any other potential issues with this way of handling things.
Related
I'm using Spring 4.3, and I have a REST Controller that returns a User object to the UI (javascript).
The problem is that I get a User object from the Database (say with Hibernate) that contains a password. I don't want to expose the password by actually returning it. Instead, I want the controller method to put NULL in it before returning it (I could use Optional or other solutions to avoid nulls, but I'm keeping it simple in this question).
public class User {
private String username;
private String password;
//setters and getters
}
#Controller
public class MainController {
#RequestMapping(value = "/user/getOne", method = RequestMethod.GET)
public User getOneUser() {
User user = //getUser
//something to nullify the password?
return user;
}
This question concerns a User and a password for clarity, but I'm looking for a wide solution that would take care of all my data models and the values I don't want them to include in some returns.
Solutions I don't like :)
Disliked solution #1: Remove the password in a private method or a utility class' method or an Adapter class
I don't like this because it makes the code very long. Most controller methods will need their own adaptation of the data.
I prefer something more clean and short.
Disliked solution #2: Use #JsonIgnore annotation
I don't want to bind my data models with Jackson package.
Disliked solution #3: Use a smaller data model class, and blind-copy everything that the smaller can contain
This solution refers to a code such as this:
public class ReturnUser {
private String username;
}
#Controller
public class MainController {
#RequestMapping(value = "/user/getOne", method = RequestMethod.GET)
public User getOneUser() {
User user = //getUser
ReturnUser smaller = copyWhatsInCommon(user, User.class, ReturnUser.class); //sees that there's only username common to both, so copies only it
return smaller;
This also increases the quantity of code, so I don't like it.
Any ideas?
Option 1:
You can add a transformation layer between your controller and the facade (or the service which populates the entity from the database). The transformation layer classes can convert the entities into value objects. The VOs will only contain the minimal information that your view needs. If there are more entities than 1 that you need to transform into value objects, you can also use reflections to read the properties (from a config file or something) that need to be read from the entities and copied to the VOs. However, this is not quite different from the solution 3 in your question that you don't like much. While it serves from performance and security perspective, it does add additional code in form of a transformation layer.
Option 2: An alternate and straightforward option I can propose is read the required attributes from 'User' class and populate them as model attributes.
#RequestMapping(value = "/user/getOne", method = RequestMethod.GET)
public User getOneUser(ModelMap modelMap) {
User user = //getUser
modelMap.addAttribute("userName", user.getName());
modelMap.addAttribute("userEmail", user.getEmail());
...
...
}
}
From experience:
1.) You should not return your business objects from the View layer ie Controller. You see this in many tutorials, but this is poor design.
2.) You should create a response object. This response object will only contain the fields you want to return to the user.
3.) You should instantiate the fields for UserResponse in the constructor with the user object.
Using since you are creating a resposne object, you using the #JsonIgnore annotation doesn't make sense.
While this may be more code, it is a better design with a clear separation of responsibility. The controller only needs to worry about the view object and the business layer never needs to know anything about the view.
Ex
public class UserResponse {
private String firstName;
private String lastName;
public UserResponse(User user){
this.firstName = user.getFirstName();
this.lastName = user.getLastName();
}
...
//The getters
}
In the controller:
return new UserResponse(user);
Why do you want absolutely to return the User as it is represented in your entity?
The service and the controller layers should even not get a User object that contains a password field. So your 1 and 3 solution should be avoided.
In your case returning a view of the User class seems the most relevant way to achieve your need. Just use a DTO
Either you could return the User DTO from a service layer that accesses to the Data Access layer.
Or if you don't have a service layer, you could provide a method in the data access layer that returns a User DTO without the password field.
I am going to offer one more solution. Just for coverage. This is very ugly and not recommended. You can create an object mapper and filter the object:
static ObjectMapper mapper = new ObjectMapper();
public static String filterOutAllExcept(Object obj, String filterName, String... properties) throws YpException {
mapper.registerModule(new Hibernate4Module());
SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.filterOutAllExcept(properties);
FilterProvider filterProvider = new SimpleFilterProvider().addFilter(filterName, filter).setFailOnUnknownId(false);
String strValue;
try {
strValue = mapper.writer(filterProvider).writeValueAsString(obj);
} catch (JsonProcessingException e) {
// handle exception
}
return strValue;
}
Then you can call it like:
String filterApplied = ObjectMapperHelper.filterOutAllExcept(user, JsonDTOFilter.SOMEFILTER, "firstName", "lastName");
This will give you a json string with the fields firstName and lastName
For example I have a bean
public class Order
{
int orderID;
String name;
}
And I have a POST operation
#ApiOperation(value = "Insert a new order", response = Order.class)
#RequestMapping(value = "/addOrder", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
#ResponseBody
public Order addOrder(#Valid #RequestBody Order order)
{
//Set random id here
order.id = 'xxxxx';
Order o = orderService.insertOrder(order);
return o;
}
And in Swagger I have the following:
So my question is, how do I hide id on POST but show ID on GET?
Or should I add a description saying that even if you choose to add an ID it wont do anything and just return my random id? Just like in Kubernetes (uid)
And properties like read-only in #ApiModelProperty will solve anything?
A simple approach is to split your bean in two - one for creating a new object, and another one which extends that for data about an existing object.
e.g.
public class IncompleteOrder {
String name;
}
public class ExistingOrder extends IncompleteOrder {
int id;
}
Then have your POST method take an object of IncompleteOrder and return one of ExistingOrder. I'd also delegrate responsibility for assigning a random order id to the underlying service...
public ExistingOrder addOrder(#Valid #RequestBody IncompleteOrder order) {
ExistingOrder o = orderService.insertOrder(order);
return o;
}
The same thing could be achieved by having two completely separate classes with no inheritance relationship, which would probably be appropriate if there was a significant divergence between the information needed to create a new order from the information which is on an existing order.
An alternative is to ask what the id is actually for - why are your clients getting integer id's for anything? Ideally, if they want any information about the order they should be querying the API for the resource, and to do that they need the URI of the order rather than the integer id. So external services communicating about an order should be passing the URIs back and forth rather than ids. Perhaps you could encourage your clients to communicate with each via the URI you return in the Location header from your POST request? Then you could do away with exposing the id on your response and have a purely symmetric request / response body.
As the title says....
I want to build a POJO with four field variables and at certain runtime events create an instance of this POJO with access to possibly maybe two or three of the fields.
public class Category implements Serializable {
private String name;
private String description;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Lets say I create a new Category object but I only want to be able to have access to the name field during runtime. Is there a design pattern I can use to achieve this? I thought about the strategy pattern and looked at the builder but I am still confused if I can do this in java.
Basically the overall goal is to grab an object from a database and return it as a JSON response in jax rs. But sometimes I dont want a complete object returned but only lets say halve of the object to be accessible at during certain runtime events. My apologies if this seems like a dumb question but I know what I want to do but just don't know the best way.
I have the same problem with you, and my project was used springmvc,and the json tool is jackson.With the problem solved, I just use #JsonIgnore.For more details,just read jackson-how-to-prevent-field-serialization
So someone correct me if I am wrong or see a better option than this...with alot of objects this can be alot of extra code for serialization and deserialization...Jackson Provisions is what I need. I can use the annotation #JsonView(DummyClass.class) on the field variable. I will accept this a the best answer in a day or two unless someone else posts a better response.
// View definitions:
class Views {
static class Public { }
static class ExtendedPublic extends PublicView { }
static class Internal extends ExtendedPublicView { }
}
public class Bean {
// Name is public
#JsonView(Views.Public.class) String name;
// Address semi-public
#JsonView(Views.ExtendPublic.class) Address address;
// SSN only for internal usage
#JsonView(Views.Internal.class) SocialSecNumber ssn;
}
With such view definitions, serialization would be done like so:
// short-cut:
objectMapper.writeValueUsingView(out, beanInstance, ViewsPublic.class);
// or fully exploded:
objectMapper.getSerializationConfig().setSerializationView(Views.Public.class);
// (note: can also pre-construct config object with 'mapper.copySerializationConfig'; reuse)
objectMapper.writeValue(out, beanInstance); // will use active view set via Config
// or, starting with 1.5, more convenient (ObjectWriter is reusable too)
objectMapper.viewWriter(ViewsPublic.class).writeValue(out, beanInstance);
This information was pulled from http://wiki.fasterxml.com/JacksonJsonViews
with jackson 2.3, I can do this with JAX-RS
public class Resource {
#JsonView(Views.Public.class)
#GET
#Produces(MediaType.APPLICATION_JSON )
public List<Object> getElements() {
...
return someResultList;
}
}
My problem concerns the creation of a custom method within an action. I'm using Struts2 and REST Plugin in order to implement a RESTful WebService. My action class is the following:
public class SampleController implements ModelDriven<Object> {
private Sample sample = new Sample();
private Collection<Sample> list;
private int id;
public HttpHeaders create() {
sdao.save(sample);
return new DefaultHttpHeaders("create");
}
public HttpHeaders destroy() {
return new DefaultHttpHeaders("destroy");
}
public HttpHeaders show() {
return new DefaultHttpHeaders("show").disableCaching();
}
public HttpHeaders update() {
sdao.save(sample);
return new DefaultHttpHeaders("update");
}
public HttpHeaders index() {
list = sdao.findAll();
return new DefaultHttpHeaders("index").disableCaching();
}
public Object getModel() {
return (list != null ? list : sample);
}
public int getId() {
return id;
}
public void setId(Integer id) {
if (id != null) {
this.sample = (Sample) sdao.findById(id);
}
this.id = id;
}
}
I can access to a resource via a GET HTTP method correctly. In order to use a custom method, called by passing a parameter to search resources i.e
public searchBySenderName(String senderName) {
list.addAll(sdao.findBySenderName(senderName))
}
What is the correct procedures? How can I call it via GET following URL?
You can call custom method from any of the predefined methods for GET (index, show) in your case, see RESTful URL mapping logic .
RESTful URL Mapping Logic
This Restful action mapper enforces Ruby-On-Rails REST-style mappings.
If the method is not specified (via '!' or 'method:' prefix), the
method is "guessed" at using REST-style conventions that examine the
URL and the HTTP method. Special care has been given to ensure this
mapper works correctly with the codebehind plugin so that XML
configuration is unnecessary.
Of course you can change the method names used by the action mapper, but it will affect a whole application. If you already occupied a resource URL then you should use another to perform its job. This is in case if you are using a strict rest mapper. In the mixed mode you can map an usual action to some action method.
REST and non-RESTful URL's Together Configuration
If you want to keep using some non-RESTful URL's alongside your REST
stuff, then you'll have to provide for a configuration that utilizes
to mappers.
Plugins contain their own configuration. If you look in the Rest
plugin jar, you'll see the struts-plugin.xml and in that you'll see
some configuration settings made by the plugin. Often, the plugin just
sets things the way it wants them. You may frequently need to override
those settings in your own struts.xml.
And last, you mightn't specify a method via ! or method: prefix because it's restricted by default configuration.
I am using Play Framework 1.2.4 with Java and using JPA to persist my database objects. I have several Model classes to be rendered as JSON. But the problem is I would like to customize these JSON responses and simplify the objects just before rendering as JSON.
For instance, assume that I have an object named ComplexClass and having properties id, name, property1,...,propertyN. In JSON response I would like to render only id and name fields.
What is the most elegant way of doing this? Writing custom binder objects or is there simple JSON mapping such as using a template?
Play Framework 1.2.4 directly depends on the gson library so you could use that to render your JSON strings. All you have to do is use gson's #Expose annotation. So in your example, you would mark the fields you want in your JSON string like this:
public class ComplexClass {
#Expose
public Long id;
#Expose
public String name;
...
}
Then in your controller, you would just do this:
public static void someActionMethod() {
// get an instance of your ComplexClass here
ComplexClass complex = ...
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()
String json = gson.toJson(complex);
renderJson(json);
}
See documentation here.
If ComplexClass is actually a play.db.jpa.Model and therefore the id field is abstracted away in a parent class and you can't put the #Expose annotation on it, then you could create your own ExclusionStrategy that skips fields that aren't annotated with #Expose and are not called id. So something like this (pseudo-code):
public final class ComplexClassExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipField(FieldAttributes attributes) {
if (name of field is "id") return false;
if (field is annotated with #Expose) return false;
return true;
}
Then the controller would altered slightly to look like this:
GsonBuilder builder = new GsonBuilder();
ComplexClassExclusionStrategy strategy = new ComplexClassExclusionStrategy();
builder.setExclusionStrategies(strategy);
Gson gson = builder.create();
String json = gson.toJson(complex);
renderJson(json);
Use FlexJSON, it's really easy. It allows you to create JSONSerializers which can include/exclude the fields you want.
Check out this article for some examples of using it with Play! Framework.
Here's a simple example:
public ComplexClass {
public Long id;
public String name;
// And lots of other fields you don't want
public String toJsonString() {
// Include id & name, exclude all others.
JSONSerializer ser = new JSONSerializer().include(
"id",
"name",
).exclude("*");
return ser.serialize(this);
}
}
You can add it to your dependencies.yml like so:
require:
- play
- net.sf.flexjson -> flexjson 2.1
What I usually do is write an interface for models that implements a toJSONString() method so that I can call renderJSON(someModel.toJSONString()) in the controller.
Link to official website
EDIT: Extra example for lists/collections
Ok, when you start serializing list you might get some unexpected results. This is because the order of evaluation is important. The first include() or exclude() takes precedence over the following ones.
Here's an example of serializing the childs of a parent entity (OneToMany relation).
JSONSerializer ser = new JSONSerializer();
// Exclude these standard fields from childs
ser.exclude(
"*.persistent",
"*.class",
"*.entityId"
);
// Include childs and all its other fields
ser.include(
"childs",
"childs.*"
);
// Exclude everything else
ser.exclude("*");
String data = ser.serialize(parent);
The * is a wildcard by the way. This piece of documentation explains it perfectly:
An exclude of *.class will match to any path depth. So if flexjson is serializing the field with path of "foo.bar.class" the * in *.class will match foo.bar.