This question may expose my lack of knowledge of AspectJ but here goes anyway :)
I have successfully used Spring Roo to Database Reverse Engineer a bunch of tables into a new Roo project. I'd like to be able to keep the round-trip-engineering aspect of Roo by not 'pushing' my aspects into plain old Java classes. However, I am experiencing an issue with assigning values to the member fields that are defined in the Aspect.
For example, I have a RooDbManaged entity class, let's call it X, and Roo has generated an aspect: X_Roo_DbManaged. Now, I want to customize a setter for the field 'updateDate' so that I can assign the date to be the current at the time of persistence. So, I have placed my custom code in the class X as follows:
public void setUpdateDate(Date updateDate) {
this.updateDate = new Date();
}
This causes Roo to remove the setter from the aspect, as I would expect, because I have now defined it in X.
This gives me an error:
The field X.updateDate is not visible
If I change the visibility of the field in the X_Roo_DbManaged aspect to 'public' (something that I'd rather not do), this resolves the issue until Roo automatically regenerates the aspect causing the error to recur.
My guess is that I'm missing something so obvious that no one has thought it worthwhile posting, as my usually successful Googling failed to find any solution for this one!
I should add that my workaround is to customize the relevant methods from the X_Roo_Controller by moving them into the XController and assigning the date there using the unmodified setter. This seems to be counter intuitive as I would really like the updateDate always to be the current date when set. Interestingly the Roo-generated #Temporal(TemporalType.TIMESTAMP) annotation on the updateDate field does not provide this functionality. I'd realy like to be able to tell Roo with a Roo command that certain DBRE fields ought to have this behavior and not have to worry about what is essentially 'plumbing'.
I suggest you use #PrePersist and #PreUpdate instead of hacking the setters
public class X {
#PreUpdate
public void beforeSaving() {
this.setUpdateDate(new Date());
}
}
Otherwise you can still put the field itself from X_Roo_DbManaged.aj into X.java file, but you will loose the ability to incrementally reverse engineer that field.
You can move the field updateDate into X.java for it to be visible.
Related
I am having problems with EclipseLink change tracking in one of my entity classes in a Java SE application. I am using Java 8, JPA 3.0 provided by EclipseLink 3.0.2 and HyperSQL 2.6.1. So far I have kept my implementation provider-independent, so switching JPA providers is an option, although not preferable.
This particular entity class has ~10 attributes of the type OverriddenValue, each of which is a wrapper for 1. a reference to a particular global configuration value, and 2. an optional custom value which will override the global value if present.
public class OverriddenValue<T> {
#Nullable
private T customValue;
private final OverridableValue<?, T> globalConfigValue;
[...]
}
This class contains getter and setter logic which would make it very inconvenient to store the custom values in the entity directly. So I need these custom values to be wrapped.
Each one of these OverriddenValues in my entity class I have marked with #Convert using a unique AttributeConverter. All of these AttributeConverters simply return the custom value for the Java -> DB mapping, and for the DB -> Java mapping they reconstruct the object with the correct global configuration OverridableValue. It is because I need the reference to the OverridableValue that I did not implement OverriddenValue as an #Embeddable - I would have either have had to persist the ID of the global configuration value, or make it transient, and I decided that was too inconvenient. Besides, each OverriddenValue really only needs one column in the database to store its custom value or null, and so #Convert should be up to the job.
My problem is that EclipseLink does not detect and persist changes to these objects. In a managed instance of this entity, a change to a basic String attribute will be automatically detected and persisted at the next call to EntityManager#flush, but a change to the customValue of an OverriddenValue will not, and these columns in the database will remain as they were.
I looked up how EclipseLink's change tracking works and found someone saying that it uses .hashCode() and .equals() to determine if an attribute has changed. So I manually implemented these in the OverriddenValue class, but they must have been wrong since the changes are still not being detected.
Momentarily abandoning provider-independence, I tried marking this entity with EclipseLink's #ChangeTracking annotation and changing the ChangeTrackingType to DEFERRED, but this only caused already-detected changes to be delayed and did not enable detection of any new ones. The other tracking types (ATTRIBUTE and OBJECT) require the entity to implement a particular interface ChangeTracker which seems like it could be helpful, but I don't quite understand how to make it work.
I have also tried setting the property "eclipselink.weaving.changetracking" to false in the persistence.xml file, on the off chance that weaving was causing the issue (I don't really understand weaving). No luck.
As a possible workaround, I could manually merge all entities of this type on application shutdown and force overwrite the values in the database. But I consider this a hack and would like to avoid it if at all possible. I feel like the ORM provider should be capable of detecting wrapped attribute changes. Does anyone have an idea where I might look next to try and fix this?
EDIT:
Here is an example of what the converter classes all look like:
#Converter
public class FooConverter implements AttributeConverter<OverriddenValue<Integer>, Integer> {
#Override
default Integer convertToDatabaseColumn(OverriddenValue<Integer> attribute) {
return attribute.getCustomValue();
}
#Override
public OverriddenValue<Integer> convertToEntityAttribute(Integer dbData) {
return Config.GLOBAL_CONFIG_VALUE.override(dbData); // Every converter references a different global variable
}
}
The method override is just an OverriddenValue factory method.
Try marking the mapping as mutable:
#Entity
public class YourClass {
..
#Convert("yourConverter")
#Mutable
private OverriddenValue value1;
..
}
Alternatively, you might modify your own save methods to clone and set the OverriddenValue instance when you know there are changes within it to be persisted.
YourClass instance = em.find(id, YourClass.class);
instance.setValue1(instance.getValue1().clone());
instance.getValue1().setCustomValue(value)
em.commit();
I added the following method to one of my application entity.
public boolean isSame(TaskUser taskUser){
//some work
}
However I came across few threads like this one regarding hibernate errors for such kind of methods used without #Transient. But my application is running fine and also there is no column created in my DB table for the entity, so as a learner I want to ask what actually happens that save my app from hibernate error. Is that argument passed the reason?
This method does not define a property, so Hibernate is not interested in mapping a column for it.
The reason is that it is not a "getter". It does have the proper name ("isXXX" for a boolean), but it takes a parameter. Getters must be without parameters.
If it was a "real" getter, and you did not want it to result in a persistent property, you could use #Transient to suppress the automatic mapping.
It is a rather general question, but I will give a stripped down example. Say I have a Web CRUD application that manages simple entities stored in a database, nothing but classic : JSP view, RequestMapping annotated controller, transactional service layer and DAO.
On an update, I need to know the previous values of my fields, because a business rule asks a for a test involving the old and new values.
So I am searching for a best practice on that use case.
I thing that spring code is way more extensively tested and more robust than my own, and I would like to do it the spring way as much as possible.
Here is what I have tried :
1/ load an empty object in controller and manage the update in service :
Data.java:
class Data {
int id; // primary key
String name;
// ... other fields, getters, and setters omitted for brevity
}
DataController
...
#RequestMapping("/data/edit/{id}", method=RequestMethod.GET)
public String edit(#PathVariable("id") int id, Model model) {
model.setAttribute("data", service.getData(id);
return "/data/edit";
}
#RequestMapping("/data/edit/{id}", method=RequestMethod.POST)
public String update(#PathVariable("id") int id, #ModelAttribute Data data, BindingResult result) {
// binding result tests omitted ..
service.update(id, data)
return "redirect:/data/show";
}
DataService
#Transactional
public void update(int id, Data form) {
Data data = dataDao.find(id);
// ok I have old values in data and new values in form -> do tests stuff ...
// and MANUALLY copy fields from form to data
data.setName(form.getName);
...
}
It works fine, but in real case, if I have many domain objects and many fields in each, it is quite easy to forget one ... when spring WebDataBinder has done it including validation in the controller without I have to write any single thing other than #ModelAttribute !
2/ I tried to preload the Data from the database by declaring a Converter
DataConverter
public class DataConverter<String, Data> {
Data convert(String strid) {
return dataService.getId(Integer.valueOf(strid));
}
}
Absolutely magic ! The data if fully initialized from database and fields present in form are properly updated. But ... no way to get the previous values ...
So my question is : what could be the way to use spring DataBinder magic and to have access to previous values of my domain objects ?
You have already found the possible choices so i will just add some ideas here ;)
I will start with your option of using a empty bean and copying the values over to a loaded instance:
As you have shown in your example it's an easy approach. It's quite easily adaptable to create a generalized solution.
You do not need to copy the properties manually! Take a look at the 'BeanWrapperImpl' class. This spring object allows you to copy properties and is in fact the one used by Spring itself to achieve it's magic. It's used by the 'ParameterResolvers' for example.
So copying properties is the easy part. Clone the loaded object, fill the loaded object and compare them somehow.
If you have one service or just several this is the way to go.
In my case we needed this feature on each entity. Using Hibernate we have the issue that an entity might not only change inside a specific service call, but theoretically all over the place..
So I decided to create a 'MappedSuperClass' which all entities need to extend. This entity has a 'PostLoad' event listener which clones the entity in a transient field directly after loading. (This works if you don't have to load thousands of entities in a request.) Then you need also the 'PostPersist' and 'PostUpdate' listeners to clone the new state again as you probably don't reload the entity before another modification.
To facilitate the controller mapping I have implemented a 'StringToEntityConverter' doing exactly what you did, just generalized to support any entity type.
Finding the changes in a generalized approach will involve quite a bit of reflection. It's not that hard and I don't have the code available right now, but you can also use the 'BeanWrapper' for that:
Create a wrapper for both objects. Get all 'PropertyDescriptors' and compare the results. The hardest part is to find out when to stop. Compare only the first level or do you need deep comparison?
One other solution could also be to rely on Hibernate Envers. This would work if you do not need the changes during the same transaction. As Envers tracks the changes during a flush and creates a 'Revision' you can "simply" fetch twp revisions and compare them.
In all scenarios you will have to write a comparison code. I'm not aware of a library but probably there is something around in the java world :)
Hope that helps a bit.
I'm developing a Scala extension to an existing Java ORM (Ebean). The goal of this project is to add as much type safety as possible to the ORM.
Instead of
Ebean.find(Product.class).fetch("name", "unit").findList()
I would finally like to be able to write something like
(objects of entity[Product] with attributes name and unit) getIt
(note that this is just a very first DSL approach).
The ORM model is already defined as
#Entity
public class {
public String name;
public String unit;
}
In order to achieve type safety at compile time for the attributes in the query, I would need to access them on e.g. a dummy object like (new Product()).name.
I think this is the best way to ensure that only such model members are used that exists on that class, but, at runtime, I need a way to recognize that this variable was accessed. Otherwise I would just call that member name and wouldn't know about this in my query.
Does anybody know a way how to achieve this? Is there a possibility to trace when a variable is accessed and to give that information, at runtime, to any other object?
I already thought about hooking into getters and setters instead of using public members in the model classes, but this would either make the query or the model very ugly. Another problem is that any additional specific methods would have to be added manually for each model.
I would be happy if anyone could suggest possible solutions. Thanks!
If you are willing to define the fields of your model objects as something like the Record Fields, what Emil suggested could work, but if you're building your solution on top of a Java ORM using custom types might be an issue. If you need to track field access I think your best bet will be runtime bytecode instrumentation using a library like CGLib or Javassist. You can pass an instrumented "dummy" object into the body of your function, then track which field was accessed in a thread local. That's how it's done in Squeryl.
You could take a gander at how the Lift folks have implemented Mapper and Records. It allows for type safe queries using companion objects (as well as using raw sql). It does require inheriting traits into your model and the fields are specified as objects and not regular vals. Might be helpfull though. You can find the source for the persistance stuff here.
In our base entity class (that all entities derive from), we have, amongst others, 2 methods. One annotatted with #PrePersist which basically just sets the dateCreated, and the other annotated with #PreUpdate which sets the dateUpdated field.
This works perfectly, as we do not wish to set the dateUpdated field on creation. As part of the design, we also make the two methods protected so that other developers don't go and explicitly mess with those two dates (also no setters).
Also, we can easily enough extend any entity to set the dateUpdated field on creation by defining a method on the actual entity and also annotate it with #PrePersist, so this part is covered.
Now, my problem at the moment is that there is a case where we would like to explicitly update the dateUpdated field on an entity, without any data on it changing (basically touch it). Is there an elegant way of doing this? I do not really want to implement a method that changes one of it's fields and then change it back. And we would like to keep having the entities without setter methods for those fields.
Thanks!
Have you tried just changing the dateUpdated field value? I guess this should make the entity modified to Hibernate, and Hibernate would call the #PreUpdate method which would set the dateUpdated field back to the current time:
public void touch() {
this.dateUpdated = -1;
}
Annotate your dateUpdated field with #Version, remove preUpdate callback and use em.lock(entity, LockModeType.WRITE) prior commiting transaction. Remamber that entity needs to be managed in order to force version column to be updated