JPA - Using null values in #DiscriminatorValue - java

I was wondering if I could use the DiscriminatorValue to set apart two subtypes in the following manner:
B extends A
#DiscriminatorValue(null)
A
#DiscriminatorValue("Some-Value")
B extends A
The point is that I want to check if there is a null value in some DiscriminatorType.Char column.
I tried writing "" (empty string) as the value and also null. Niether worked.

The DiscriminatorValue is normally set by the implementation, and you should only need to set it when the implementation cannot properly tell two classes apart, like having duplicate class names or very long class names.
For example, in Hibernate/Postgres, the default discriminator is the simple class name. The only time I have ever had to set it is in deeply nested classes that run on longer than the name limit in the database.
So, long story short, don't specify a discriminator value unless you must.

Annotation do not allow a null indicator, nor does the spec directly support it.
If you are using EclipseLink, you should be able to use a DescriptorCustomizer to add a null classIndicator mapping to the A's ClassDescriptor's inhertiancePolicy.

Related

EclipseLink not tracking changes to converted wrapper attributes

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();

Map a column in Hibernate without a property in the Java class

Is it possible to map a database column using Hiberanate, so I can use it in HQL queries, but not map it to an actual property in the mapped class?
I don't need this attribute in my class and would like to avoid the clutter of getter and setter, which never should get used anyways.
The usecase I have is to set a flag on certain rows, so a different process will pick up the row and process it. We just have to do an update on the field like this:
update FJ345KJ set wrkxGrumble=1
where wrkxGrumble = 0
and -- more constraints comming here
Since the table and column names forced upon us by the database resemble hashcodes we want to use HQL for the update, which can use nice mapped names. Therefore we need the column mapped in Hibernate.
As far as I know this is not possible. Any mapped column needs a variable in the class.
What you can do is: You map the column with the attribute access = "field" and in the class you declare the variable as private. Then there still is a useless variable declared (this is not a performance issue as the database has to load the row anyway), but no getter and setter is necessary, and as the variable is declared as private it does not influence the interface of your java class, i. e. it is not visible for other classes.

How to make Hibernate ignore a method?

This question is essentially the opposite of this one.
I have a method like so:
public boolean isVacant() {
return getEmployeeNum() != null && getEmployeeNum().equals("00000000");
}
When I load it up, Hibernate is complaining that I have no attribute called vacant. But I don't want an attribute called vacant - I have no need to store that data - it's simply logic.
Hibernate says:
org.hibernate.PropertyNotFoundException: Could not find a setter for property vacant in class com.mycomp.myclass...
Is there an annotation I can add to my isVacant() method to make Hibernate ignore it?
Add #Transient to the method then Hibernate should ignore it.
To quote the Hibernate Documentation:
Every non static non transient property (field or method depending on the access type) of an entity is considered persistent, unless you annotate it as #Transient.
RNJ is correct, but I might add why this happens:
I'm guessing that you have annotated the getters of your persistent class. The prefixes used by java beans are "set" and "get", which are used do read and write to variables, but there is also the prefix "is", which is used for boolean values (instead of "get"). When Hibernate sees your getter-annotated persistent class, and finds a method "isVacant", it assumes that there is a property "vacant", and assumes that there is a "set"-method as well.
So, to fix it, you could either add the #Transient annotation, or you could change the name of your method to something that doesn't start with "is". I don't think this would be a problem if your class was annotated on the fields, instead of the get-methods.
Many frameworks (like Hibernate and Drools) are smart enough understand that Boolean variables need to be accessed by "is" instead of "get". But they don't always understand perfectly, and that is when "interesting" problems can develop. Or, worse yet, the different frameworks interpret the methods slightly differently, and they are supposed to work together.
BTW, the #Transient solution is not guaranteed to solve all your problems. Most notably, say that you are adding it to a toString() that returns a huge and complex object. You might be getting a stack overflow not because the method is huge and complex, or even because all the sub-obejcts have their own toString() methods, but because your structure has circular structures. That is what causes the stack overflows.

How to use reflection to retrieve private variable property from JPA objects

One of my goals is to create an engine that will set values in pojo object from JPA objects dynamically using reflection. One of the matching criteria is, that the field names should match.
I was successfully able to implement this for two pojo objects. But when I tried using JPA objects as one of the object parameter, it didn't work. Based on my research I found out that the method Class.getDeclaredFields() , does not give me the name of the field but the getter/setter method name of member variable for JPA objects.
Can anyone please give me a lead or direction as in where/what should I look to accomplish this task?
JPA providers will often use dynamic proxy classes of your concrete JPA classes, so you have no guarantee of the field names in the proxy. The only guarantee about a proxy is that the methods are the same. Use a debugger to inspect the runtime class of the JPA class instances that you're trying to use and you'll see the problem.
The best you'll be able to do is use reflection to call methods on JPA-returned objects.
All that aside, I don't really see why you'd need to POJO-ify an entity class anyway, since an entity is primarily an annotated... POJO.
One of the matching criteria is, that the field names should match.
I think that this is the root of your problem. There is simply no guarantee that a Java object's field names will match the names of getters and setters ... or anything else. If you make this assumption, you will run into cases where is doesn't work.
The best solution is to simply not use this approach. Make it a requirement that the Pojo classes conform to the JavaBeans spec and rely on the setters to set the properties. This is likely to work more often than making assumptions about (private) field names.
In fact, the state of a generic JPA object implemented using a dynamic proxies could well be held in a hash map. Those fields you can see could simply be constants used for something else.

Structural design pattern

I'm working with three separate classes: Group, Segment and Field. Each group is a collection of one or more segments, and each segment is a collection of one or more fields. There are different types of fields that subclass the Field base class. There are also different types of segments that are all subclasses of the Segment base class. The subclasses define the types of fields expected in the segment. In any segment, some of the fields defined must have values inputted, while some can be left out. I'm not sure where to store this metadata (whether a given field in a segment is optional or mandatory.)
What is the most clean way to store this metadata?
I'm not sure you are giving enough information about the complete application to get the best answer. However here are some possible approaches:
Define an isValid() method in your base class, which by default returns true. In your subclasses, you can code specific logic for each Segment or FieldType to return false if any requirements are missing. If you want to report an error message to say which fields are missing, you could add a List argument to the isValid method to allow each type to report the list of missing values.
Use Annotations (as AlexR said above).
The benefit of the above 2 approaches is that meta data is within the code, tied directly to the objects that require it. The disadvantage is that if you want to change the required fields, you will need to update the code and deploy a new build.
If you need something which can be changed on the fly, then Gangus suggestion of Xml is a good start, because your application could reload the Xml definition at run-time and produce different validation results.
I think, the best placement for such data will be normal XML file. And for work with such data the best structure will be also XMLDOM with XPATH. Work with classes will be too complicated.
Since java 5 is released this kind of metadata can be stored using annotations. Define your own annotation #MandatoryField and mark all mandatory fields with it. Then you can discover object field-by-field using reflection and check whether not initiated fields are mandatory and throw exception in this case.

Categories