I am trying to create a web service using JAX-WS (SOAP) allowing CRUD operations on some entities. I am also writing a desktop client with an UI which provides easy means of doing CRUD on those entities via the web service.
However, I am running into some design issues. I would like the client to only be able to view and manipulate certain fields of an entity, and I'm not sure what's the best way to impose this restriction.
For instance, given:
@Entity
public class Customer {
@Id
@GeneratedValue
public Long id;
public String name;
// neither read nor write from the web service
public String password;
// read-only from the web service
@Temporal(TemporalType.DATE)
public Date joinedAt;
@ManyToOne
@LazyCollection(LazyCollectionOption.FALSE)
private List<Order> orders;
// .. boilerplate getters and setters
}
@Entity
public class Order {
@Id
@GeneratedValue
public Long id;
public String name;
}
I would like to provide the client with these basic operations:
- get the list of all customers with their orders
- he can see all the fields EXCEPT for
password
- he can see all the fields EXCEPT for
- create a new customer with some orders
- allow control to all fields EXCEPT FOR
joinedAt
andpassword
- allow control to all fields EXCEPT FOR
- modify a customer
- same as above, you're not allowed to modify
joinedAt
orpassword
- same as above, you're not allowed to modify
.
My current solution for (1) is to add @XmlTransient to the password field. This is problematic if you want to send the password to certain clients but not to others. Another solution would be to do
customer.setPassword(null);
before marshalling that entity via the webservice. But is this really the way to do it? A third solution would be to create a base classBaseCustomer
which contains all the fields except forpassword
and then Customer would be aBaseCustomer
with the addedpassword
field. The user would receive a BaseCustomer object instead of a Customer one. But this has problems with create/update as well.Same as for (1), one solution is to do
customer.setJoinedAt(my_value); customer.setPassword(my_value); customer.setId(null);
when the client wants to create a new customer. Is manually nulling theid
really best practice? I find that hard to believe. Should theid
be XmlTransient as well? But then how would the user of the web service be able to modify/delete entities?When the client wants to change a
Customer
, he retrieves the list of customers, makes changes to one of theCustomer
objects, then marshals that object and passes it back to the web service. There are a few problems with this: if theid
field is XmlTransient, then the EntityManager's persist won't know which row to modify and would likely create a new one. A similar issue raises if the user is evil and simply refuses to pass anid
, so I have to manually check that theid
is non-null. Moreover, the user has not received thepassword
field, so now the server has received an object with a nullpassword
field which it will attempt to persist. I believe this will cause the EntityManager to completely remove the password of that existing Customer. Having the user specify exactly which fields he wants modified and to which values seems impractical.
Note that this is just a proof-of-concept of what I need to do in a nutshell, I have far more entities, relations and operations to provide.
I am new to using these technologies and I was hoping that being so high level and having so many abstractions would make my life easier, but so far it has been mostly headaches. It appears very difficult to achieve this common, basic task. Am I doing something wrong? Please don't suggest creating a web application instead :)