I have created a POJO class in morphia to save data object to MongoDB ,
I have a property called 'unitPrice', i want to keep this as read only property, mean not allow to modify DB value once it save to mongo,
Is there a morphia annotation to do this or else,
Is it possible to bind #NotSaved annotation to the property at run time ?
This is my POJO
#Entity("items")
public class Items {
private int id;
private int sequence;
private int unitPrice;
}
Thanks
BR
Ero
I don't know of a way to bind #NotSaved at runtime, but I could think of a (hacky) workaround:
Set the attribute in the constructor (Morphia will still require the no-args constructor)
Don't provide a setter, just a getter for the attribute
It ain't pretty, but it should get the job done.
Related
I have the following bean that describes a mongo document, and that uses lombok:
#JsonDeserialize(builder = MyClass.MyClassBuilder.class)
#Builder(toBuilder = true)
#Value
public class MyClass {
private final String id;
#Default
private final String field = "defaultValue";
#JsonPOJOBuilder(withPrefix = "")
public static class MyClassBuilder {}
}
When deserializing {"id": "document"} with jackson, I end-up with a bean containing both id=document and field=defaultValue because it used the builder that provide a default value for the field.
Now what I want to do, is to have the defaultValue set for documents coming out of the database (coming from ReactiveMongoTemplate). But it seems to use the all args constructor even if I set it private (or some reflect black magic)
So the main question is: is it possible to tell spring to use the builder to build the bean when coming out of the database?
You are not going to be able to use your custom serialiser because when I go through the source code of MappingMongoConverter in spring mongodb (debugged it with a sample app) , I see only the following steps.
Once the value from db is available as org.bson.Document, MappingMongoConverter.java is looking to create your entity object.
First, it checks if you have any custom converters registered and if you have it, then use it. So one option is to use a custom converter registered.
If there is no custom converters registered, it goes and find the PersistenceConstructor and use it. I had an object with 3 constructors (no param, one param, and all param) and it chose my no param constructor.
However, if I annotate a constructor with #PersistenceConstructor, it is choosing that constructor. So could follow this approach but then you have to keep String field un-initialised and getting initialised differently in each constructor
MappingMongoConverter.java
conversions.hasCustomReadTarget
persistenceConstructor
If I have a class using Lombok:
#RequiredArgsConstructor
#Getter
class Example {
private final String id;
}
And try to deserialize it from
{
“id”: “test”
}
Jackson throws an exception that although at least one creator was provided, it could not deserialize.
If I then add another final String field to that class, and add that field to the JSON, it is deserialized with no complaints.
Does anyone know what’s going on here? Why are you unable to deserialize if you only have one field?
When only way to intialize object properties is through contructor, Jackson needs to be told that deserialization should happen using constructor via #JsonCreator annotation.
Also, all the property names should be provided via #JsonProperty annotation because Jackson needs to know the sequence of attributes passed in contructor to correctly map json values to Java object attributes.
So, if you are not using lombok contructor, then constructor will look like
#JsonCreator
public Example (#JsonProperty("id") String id) {
this.id = id;
}
If you don't want to manually write the contructor, go ahead with #tashkhisi's answer.
Also, I highly doubt following could happen. Could you update the question with code showing this?
If I then add another final String field to that class, and add that field to the JSON, it is deserialized with no complaints.
I'm working on a JPA project. I have an ExportProfile object:
#Entity
public class ExportProfile{
#Id
#GeneratedValue
private int id;
private String name;
private ExtractionType type;
//...
}
ExtractionType is an interface implemented by several classes, each for a different extraction type, these classes are singletons.
So type is a reference to a singleton object. I don't have an ExtractionType table in my DB, but i have to persist the extraction type of my export profile.
How can I persist the ExportProfile object using JPA, saving the reference to type object?
NOTE: The number of ExtractionType implementations is not defined, because new implementation can be added anytime. I'm also using Spring, can this help?
Here's an idea: make an ExtractionTypeEnum, an enumeration with one element for each of the possible singletons that implement ExtractionType, and store it as a field in your entity, instead of ExtractionType . Later on, if you need to to retrieve the singleton corresponding to a ExtractionTypeEnum value, you can implement a factory that returns the correct singleton for each case:
public ExtractionType getType(ExportProfile profile) {
switch (profile.getExtractionTypeEnum()) {
case ExtractionTypeEnum.TYPE1:
return ConcreteExtractionType1.getInstance();
case ExtractionTypeEnum.TYPE2:
return ConcreteExtractionType2.getInstance();
}
}
In the above, I'm assuming that both ConcreteExtractionType1 and ConcreteExtractionType2 implement ExtractionType.
I have one Pojo class in which I create one field which is not mapped with DataBase Table.
So i have to declare the field Declaration and setter and getter method #Transient, otherwise it would have shown an error.
#Transient
private String docHistoryString="";
#Transient
public String getDocHistoryString() {
return docHistoryString;
}
#Transient
public void setDocHistoryString(String docHistoryString) {
this.docHistoryString = docHistoryString;
}
Now, my problem is in the controller. I have set some value in this transient field but when I try to access this variable using EL in view(JSP) it is not giving value. I think this is becouse I used the #transient annotation in get method.
All Hibernate annotations, including #Transient must be applied according to access type. By default it will be the same way as #Id applied. That is if you place #Id on a field you must apply #Transient to the field. And if you apply #Id to getter method, you must apply #Transient method. Setter methods are always ignored.
It can be customized, though (per documentation), so make sure that someone didn't do something strange with access types.
According to this, it should be enough to declare the field/property
http://download.oracle.com/javaee/5/api/javax/persistence/Transient.html
Have you tried with just annotating the field/property? For further Help you have to post some more code snippets.
I have a class to map a table for using hibernate. There are some variable I want to ignore for mapping to use as constant. And I want to load constant value from properties so I code it like this:
#Transient
#Value("${something.value}")
private int MY_VALUE;
But, the value of MY_VALUE is always set to 0. Can't I use #Transient annotation with #Value annotation? Or I missed something else?
Those two annotations belong in different domains.
#Transient belongs to an entity, while #Value belongs to Spring Beans. Entities are managed by JPA / Hibernate, Spring Beans are managed by Spring. It is not a good idea to mix the two.
You could achieve this by using the #Configurable annotation and AspectJ compilation or Load Time Weaving, but I would strongly advise against such a hack. Use a Spring Bean to hold a #Value, not an entity!
You use #Value to specify a property value to load when Spring creates the bean.
However, if you are using Hibernate to load data from a database, Spring is not instantiating these classes for you. So your #Value annotation has no effect.
I would suggest injecting the #Value into the DAO that loads these entities from Hibernate, something like
public class FooDao {
#Value("...")
private int yourConfiguredValue;
public getFoo() {
Foo foo = sessionFactory.getCurrentSession().get(...);
foo.setYourValue(yourConfiguredValue);
return foo;
}
}
In my scenario I have a class Employee which has relation with class Organization.
I don't want to serialize a whole dependent object(Organization), rather serialize a single parameter of organization(e.g. orgID).
I tried following:
#Transient
#value("#{target.orgId.id}")
private UUID org_Id;
but it didnt work. So i used a simple getter mehtod instead of a field variable as follows:
#JsonIgnore
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "orgID")
private Organization orgId;
#JsonProperty("orgId")
public UUID getOrg_ID() {
return orgId.getId();
}
it worked and i got simple orgId field in response serialized by Jackson.
It seems Jackson work with getters without considering a field variable is declared or not corresponding to that getter method.