2

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:

  1. get the list of all customers with their orders
    • he can see all the fields EXCEPT for password
  2. create a new customer with some orders
    • allow control to all fields EXCEPT FOR joinedAt and password
  3. modify a customer
    • same as above, you're not allowed to modify joinedAt or password

.

  1. 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 class BaseCustomer which contains all the fields except for password and then Customer would be a BaseCustomer with the added password field. The user would receive a BaseCustomer object instead of a Customer one. But this has problems with create/update as well.

  2. 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 the id really best practice? I find that hard to believe. Should the id be XmlTransient as well? But then how would the user of the web service be able to modify/delete entities?

  3. When the client wants to change a Customer, he retrieves the list of customers, makes changes to one of the Customer objects, then marshals that object and passes it back to the web service. There are a few problems with this: if the id 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 an id, so I have to manually check that the id is non-null. Moreover, the user has not received the password field, so now the server has received an object with a null password 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 :)

  • I would recommend against transferring objects as entities over soap. Consider using transfer objects: map data from entities to the transfer objects. – Sami Korhonen Nov 20 '12 at 20:58
  • 1
    But wouldn't that cause a lot of code duplication? Or would the entities inherit the transfer objects? Also, wouldn't I have to manually write a lot of `entityobj.setField(transferobj.getField())` to convert from one to the other? Is that okay? – user1792968 Nov 20 '12 at 21:07
  • If the problem domains are different, having two identical lines of code should not be considered as code duplication - proper use of transfer objects can and will make your code more verbose. With entities you are limited to following operations: getCustomer() and getCustomerOrders() while with transfer objects you could write operations that have business meaning such as: getCustomerDetails() and getCustomerDetailsWithOrderSummary(). And yes, you will have to write a lot of mapping code manually - it's perfectly ok. Consider creating separate classes for mapping. – Sami Korhonen Nov 20 '12 at 21:45

0 Answers0