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
create a new customer with some orders
allow control to all fields EXCEPT FOR joinedAt and password
modify a customer
same as above, you're not allowed to modify joinedAt or password
.
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.
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?
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 :)
Related
I am learning hibernate with spring. While implementing i am creating entity class like below
#Entity
#Table(name = "USER_DETAILS", uniqueConstraints = #UniqueConstraint(columnNames = "USER_ID"))
public class UserInfo implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "USER_KEY", unique = true, nullable = false)
private Long userKey;
#Column(name = "USER_ID", unique = true, nullable = false)
private String userId;
//getters and setters
}
And i am designing a html page to get above input from user. As per the tutorial they are creating a DTO class with same variables which are in the DAO entity class and implementing JSR303 validation after that attaching that DTO to the form like below.
<sf:form action="/addUser" commandName="userDTO"
method="post">
//input text boxes
</sf:form>
Its difficult to understand why we need to create a same DAO Entity class again without hibernate annotations and the same variables in the name of DTO. Please share some guidelines.
Is it a best practice or is it any performance / structural reason that we need to create DTO class for html form.
What will happen if we directly attach DAO entity class with form.
Please give some ideas / guidelines.
The simple answer to this question:
consider an example:
To get a summary of customer orders, That would have each row be taken from entities such as customers, addresses, products, orders etc. In such a case it is wasteful and slow to load all the entities to memory to render them in the flat search results screen.
Now, whenever the view changes it's not possible to change the entities(it will be time-consuming) but DTOs can be updated or deleted easily when as they are only used to fetch data and render them.
It is strongly recommended putting as much business logic into entities and try to have all the code which creates and connects entities default/package protected and as hidden as possible. When you do that you get the better OO design. An example would be the Order entity has a method getOrderItems to list the OrderItem entities but a protected setOrderItems method. The client would invoke a public method on the Order called addItem which took all the fields needed to construct the OrderItem entry internally using a protected constructor and add it into its list of order items. The Order becomes a "root/aggregate entity" which manages the relations and business logic of subordinate entities. This is a more naturally OO design than having "behaviourless" DTOs with the business logic entirely in service classes; or worse spread out across UI code. Have the service classes that query and load root entities then call method on the root entities that contain the business logic. That way different service class methods that work with the same root entities won't duplicate logic as the logic will be within the entities that are shared.
In simple words: If your entities are dumb with no logic then they are just DTOs.
For simple application like pet application you can use entity for web layer.
The first problems came when you add N-to-Many relation in your entity model.
Hibernate use interfaces list Set , but with it's own implementation like PersistentSet that has keep information about hibernate session, also you web part /level should has hibernate jar to work with this implementation of set :)
Lazy loading. if you close hibenate session you will get LazyInitializationException , you avoid this you should keep your hib session open till you not finish work with entity in web level
In my opinion it's bad that we link dao entity classes with mvc form.
It's a better idea to segregate your application to some layers. The most usual approach is to have 3 layers: persistence, service and presentation layers.
Typically, each layer uses its own kind of objects:
persistence: repositories, entities
business: services, domain objects
presentation: controllers, DTOs
We need this because we want each layer to be separated from the other layers. If you want to use entities in your controller, your presentation would depend on how your data is stored. It's really bad. It shouldn't even know that or how data is stored.
Suppose I have a User class:
#Entity
public class User {
#Id
private int id;
private String name;
//Other fields and methods
}
At one point of time, the name is say 'XYZ' and at other point of time its 'ABC'. I want to keep track of both the states just as we track files under version control system. These objects are stored in relational database. A crude approach which I could think of is to put the data of database itself under version control, but that's just not feasible as database table will have data for many such users and change in even any one of them will call for committing an update.
How can I achieve this? How do applications usually store edit history when they have to?
Thanks!
if you are using hibernate you could use envers
Environment:
Java
Spring
MVC pattern
Hibernate
Description:
Ok, let's say I have a web application with two domain objects:
User
Report
a User can have a lot of Reports (one to many relation). Please consider that a Report is a very complex object, with a lot of attributes.
User class:
public class User {
private Set<Report> reports = new HashSet<Report>();
}
Report class:
public class Report {
//...so maaaaaaany attributes
private String name;
}
Let's say I need to show an html page displaying a User profile with the list of associated Reports. Only reports' names appear in the list. Please comment these considerations:
I don't think to eagerly load the Reports because of memory saving issues, so I'll go lazy.
Even if I go lazy, the point is that I actually need the reports'name only. I don't want to load tons of information just to cherry-pick the report name!
So a possible solution is to modify the User class as follows:
public class User {
private Set<Report> reports = new HashSet<Report>();
private List<String> reportNames;
}
taking the needed information from the report to the user. In my opinion, it brings two consequences:
the list of report names must be kept updated
i break the separation between objects domain, filling the User with information I can't easily retrieve. This approach might even be effective, but it is very ugly.
So is there a nice solution to cope with this problem? I think it is common issue for developers.
One way would be to use the following pattern:
Create a view object which represents exactly what you want to be displayed, let's call it UserViewObject. I would not modify the domain objects just to adapt them for the view, that would break the MVC design.
Implements a service method in a service class which returns a list of UserViewObject.
Let the service method call a DAO method in a DAO class that actually does the job.
The DAO method could make sure to only read the required data, or you could do that transformation in the service layer. It is really a bit of what you prefer, and how it fits in. But do not make the DAO layer aware of your UserViewObject.
Let's say I have a User entity with an id and a version managed by hibernate, plus a firstname and a lastname.
I want to have CRUD operations on User instances with a RESTful API but I don't want the client to get the user's id and version stored in the database.
A simplistic solution I can think of is to send a representation of the user with modified id and version and to map the "public" values with the database values in a HashMap that lives in the server's memory. I also though of cookies, but I don't think it's a secure solution as they can be hacked by the client. AFAIK, a pure RESTful API must not handle session state on the server.
Is there a secure, scalable and RESTful way to publish resources without exposing their real ids and versions ?
Difficult one. You need the id or some representation of it somewhere in the URI to make GET requests.
Why are you worried about your users obtaining the real id?
One thing you could do is encrypt the user's id before it is sent to the front end and decrypt id in the back end using a symmetric encryption algorithm like AES.
See Symmetric-key algorithm
The best solution is to separate your UserEntity and UserData:
#Embeddable
class UserData {
String firstName;
String lastName;
... // getters and setters
}
// your mapped class
class UserEntity {
int id;
int version;
UserData data;
// getters and setters
}
If you're set on 'true' REST then you need to provide the client with the entire state of the object that they'll need to perform an action on it at a later time. Have you considered just applying a salt and some symmetric encryption to fields that you don't want users to be able to modify? Passing the hashes around will increase your payload size obviously, but everything comes with a cost, especially security!
I'm trying to create a domain object that contains objects in a read-only fashion but be able to modify which objects it points to.
So in the example below I would like Hibernate to handle populating the Account and Category objects but I don't want to ever update those objects. However I may wish to change which Account or which Category I want Expense to point at.
In other words I may wish to update the account_id or category_id on the expense table but I never want to update the account or category table with changes I've made on the Account or Category objects contained in the Expense object.
#Entity
#Table(name = "expense")
public class Expense {
#Id
#GeneratedValue
private long id;
private String name;
private BigDecimal amount;
#OneToOne
#JoinColumn(name = "id", referencedColumnName = "category_id")
//From table called category
private Category category;
#OneToOne
#JoinColumn(name = "id", referencedColumnName = "account_id")
//From table called account
private Account account;
Am I totally misusing Hibernate or is it just not the right tool? Should I define my own sql with #SQLUpdate and #SQLInsert?
The general flow of the application is standard web app stuff.
Load data from database
Display on form
Gather changes made by user
Persist those changes
Thanks
It is a bit of a departure from the intent of hibernate. Changes to persistent objects, are supposed to be persistent. Don't change them if you don't want their state to be saved! Explaining and thus better understanding for yourself why you want that kind of behavior might help you arrive at a solution (or help us help you.)
One option you have is to detach/evict the mapped objects that you don't want to be changed inside your data access layer before returning the Expense object. Then as long as no cascading is on, changes made to them won't be saved. IMO this leads to "surprising" behavior for other programmers.
Another option is to use hibernate in a Sessionless manner. Each call is its own atomic database operation and all objects are detached after returning. Then only entities that you explicitly call saveOrUpdate on will get saved to the database. You can learn how to configure Hibernate to work this way in the Hibernate reference docs, although again, I don't know why you'd want to if you're not trying to emulate the behavior of some legacy system you're uplifting.
One final point to understand, withing a Session, the Category that you get by calling expense.getCategory() will usually be the same actual object that you get by calling session.get(Category.class, 123). So if both ways of accessing it are available inside the same Session, it will be easy to lose track of its entity state if you're trying to manually manage it.
edit:
Ah-ha! Now it makes more sense.
If you're doing purely CRUDy web form screens, you don't have much to worry about. As long as you don't have any Cascading on, when you merge back the detached Expense object, changes on the Category and Account aren't going to end up in the database. You could null out every other field, and as long as the id is still there, you're ok. (Assuming you don't have other things like cascading validation that would cry about it.)
There are two basic patterns for handling this a little bit better.
One is to put the Expense object on the user's web session. This way you have the entire thing, and your web data binding framework only needs to bind back onto it the fields that are actually changed by the form. The original Category and Account are still there (or proxies of them) and the binder doesn't need to munge them. Downside is of course adding server side state, as well as needing to clean it up.
Two is to register data binders that actually go into the database and get the mapped entity during web binding. So all that would actually appear in the form is the ID of the mapped field, and the binder will go fetch and put the full object there for you. Downside is possibly unneeded round trips to the database, but aggressive L2 caching can fix that (assuming Categories almost never change and Accounts rarely change.)
You may also want to look into the OpenSessionInView/OpenEntityManagerInView patterns if you're presently using hibernate in an essentially sessionless manner by creating and disposing sessions within the DAO.