#Value
#Builder
public class XXX {
String field1;
String field2;
String field3;
}
I have a class using lombok #Value as above, where each field will be made private and final. Now, I'd like to have a setter for field3, which does not work because field3 is final. What should I do here?
Don't use #Value then. #Value is for value classes, i.e., classes whose instances are immutable. If you want a field to be mutable, then you clearly don't have a value class.
Instead, make all other fields final manually. Then use #Getter and #RequiredArgsConstructor (and #EqualsAndHashCode if required) on the class, and #Setter on all non-final fields. (Or use #Data, but carefully read its documentation.)
I used #NonFinal and #Setter to achieve this without adjusting too much and staying in the lombok workflow.
I had a large model that I didn't want to refactor to have final variables on everything, so this was the simplest and cleanest solution for me.
#Value
#Builder
public class XXX {
String field1;
String field2;
#NonFinal
#Setter
String field3;
}
Why is the field3 final? When a variable is declared with final keyword, its value can’t be modified, essentially, a constant. You should remove it!
Here you set the properties when you create the object
XXX s= XXX.builder().field1("XX").field2("XX").field3("XX").build();
setter are not needed here
Related
PROBLEM: I have read-only data in a table. Its rows have no id - only composite key define its identity. I want it as a Value Object (in DDD terms) in my app.
RESEARCH: But if I put an #Embeddable annotation instead of #Entity with #Id id field, then javax.persistence.metamodel doesn't see it and says Not an embeddable on Metamodel metamodel.embeddable(MyClass.class);. I could wrap it with an #Entity class and autogenerate id, but this is not what I architectually intended to achieve.
QUESTION: Is JPA Embeddable a Value Object? Can Embeddable exist without a parent Entity and represent a Table?
There are many articles on the topic that show this is a real JPA inconvenience:
http://thepaulrayner.com/persisting-value-objects/
https://www.baeldung.com/spring-persisting-ddd-aggregates
https://paucls.wordpress.com/2017/03/04/ddd-building-blocks-value-objects/
https://medium.com/#benoit.averty/domain-driven-design-storing-value-objects-in-a-spring-application-with-a-relational-database-e7a7b555a0e4
Most of them suggest solutions based on normalised relational database, with a header-entity as one table and its value-objects as other separate tables.
My frustration was augmented with the necessity to integrate with a non-normalized read-only table. The table had no id field and meant to store object-values. No bindings with a header-entity table. To map it with JPA was a problem, because only entities with id are mapped.
The solution was to wrap MyValueObject class with MyEntity class, making MyValueObject its composite key:
#Data
#Entity
#Table(schema = "my_schema", name = "my_table")
public class MyEntity {
#EmbeddedId MyValueObject valueObject;
}
As a slight hack, to bypass JPA requirements for default empty constructor and not to break the immutability of Value Object, we add it as private and sacrifice final modifier for fields. Privacy and absence of setters conforms the initial DDD idea of Value Object:
// #Value // Can't use, unfortunately.
#Embeddable
#Immutable
#AllArgsConstructor
#Getter
#NoArgsConstructor(staticName = "private") // Makes MyValueObject() private.
public class MyValueObject implements Serializable {
#Column(name = "field_one")
private String myString;
#Column(name = "field_two")
private Double myDouble;
#Transient private Double notNeeded;
}
Also there is a handful Lombok's #Value annotaion to configure value objects.
I have an entity:
#Entity
public class Test {
#Embedded
Content content;
// getters setters..
}
This contains an embedded class as you can see:
#Embeddable
public class Content {
#OneToOne
Person person;
#Embedded
Language language;
// getters setters..
}
This contains again an embeddable. 2 times nested embeddable
#Embeddable
public class Language {
String format;
#OneToOne
IdentifierCode identifierCode;
// getters setters..
}
When using the automatic schema generation feature of JPA all columns are generated in the correct way.
I use the #Data annotation on each #Entity and #Embeddable to generate getters, setters, constructors, etc..
When starting the application server (EAP 7), I notice this warning in the logs:
HHH015011: Unable to locate static metamodel field :
org.package.Language_#identifierCode; this may or may not indicate a
problem with the static metamodel
Indeed, when opening the metamodel class Language_; no identifierCode column reference is present:
#Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
#StaticMetamodel(Language.class)
public abstract class Language_ {
public static volatile SingularAttribute<Language, String> format;
}
I don't see what I'm doing wroing. Is it not possible to use #OneToOne in a nested #Embeddable? The metamodel Content_ correctly generates the singular attribute for person!
It seems when using multiple nested embeddables, something goes wrong. When using only one level of embeddables, it works.
I tried other stuff:
Adding Access.Field on the class. Nothing happens.
Instantiation the #Embedded class, like #Embedded Language language = new Language(). Nothing happens.
Replaced the #OneToOne with #ManyToOne. Nothing happens.
This sounds like a bug in your JPA provider, which you should report to them.
The JPA provider I use (DataNucleus) creates a
public static volatile SingularAttribute<Language, mydomain.model.IdentifierCode> identifierCode;
One option you have is to just use the datanucleus-jpa-query.jar in your CLASSPATH to generate the static metamodel and use those generated classes with your existing provider, alternatively use it for persistence too.
I am trying to create a subtype query along the following lines, but tyre is coming back as null even if I set #QueryInit("tyre") on the wheel property of car.
QWheel wheel = QCar.car.wheel;
QTyre tyre = wheel.as(QRoadWheel.class).tyre;
BooleanExpression tyreFittedOverYearAgo
= tyre.fitted.lt(today.minusYears(1));
Iterable<Car> carsWithOldTyres = repo.findAll(tyreFittedOverYearAgo);
How do I get QueryDSL to initialise tyre when it is accessed using as()?
By default Querydsl initializes only direct reference properties. In cases where longer initialization paths are required, these have to be annotated in the domain types via com.mysema.query.annotations.QueryInit usage. QueryInit is used on properties where deep initializations are needed.
#Entity
class Event {
#QueryInit("customer")
Account account;
}
#Entity
class Account{
Customer customer;
}
#Entity
class Customer{
String name;
String address;
}
This will intialize customer.name ,customer.address
I've not been able to establish why, but I've now got things working but by using:
#QueryInit("*")
Tyre tyre;
I have a model in play framework
public class XYZ extends Model
{
#Id
public int a;
public String field1;
public String field2;
}
In my index.scala.html I need to generate field1 and field2 dynamically.
I have an object xyz of XYZ class.
I need to get the value of xyz.field1.
I generate the string field1 dynamically in my code using "field".concat("1") and now I need to convert this string to a field so as to call xyz.field1.
I am not able to figure out how to do this conversion in my scala.html file.
You can use reflections to get a field by its name, even in a template.
#classof[XYZ].getField("field" + fieldNum).get(xyz)
If you have only a two fields, a simple if/else would probably a better way to get the fields values. If it's more complex create a method in your model and use some switch statement or a map, like Mikesname suggested.
While developing an Eclipse GEF application using an eclipselink implementation of JPA i have found an error that has been annoying me for a while:
I have three different classes:
The first one represents a variable contained in a model:
#Entity
public class Variable extends AbstractVariable{
#Id
#Generated value
private int id;
/** Lots more of stuff */
#ManyToOne(cascade=CascadeType.ALL)
Model model;
//Setters, getters and the other functions.
}
And another subclass of the abstractvariant class, which is a variable which can hold a concatenation of variables.
#Entity
public class VariableList extends AbstractVariable{
#Id
#Generated value
private int id;
/** Lots more of stuff */
#ManyToMany(cascade=CascadeType.ALL)
List<AbstractVariable> variables;
//Setters, getters and the other functions.
}
The second class, a gef editpart that can hold a variable value.
#Entity
public class VariableEditPart{
#Id
#Generated value
private int id;
/** Lots more of stuff */
VariableList vars;
//Setters, getters and the other functions.
}
And a last class with the gef model:
#Entity
public class Model{
#Id
#Generated value
private int id;
/** Lots more of stuff */
#OneToMany(cascade=CascadeType.ALL)
List<Variable> availableVars;
#OneToMany(cascade=CascadeType.ALL)
List<VariableEditPart> editParts;
//Setters, getters and the other functions.
}
The issue here is that JPA creates a table for the relation variablelist-variable, and another relation with the editpart and the variablelist, so, as soon as I try to update the model at the database after some modifications, It tries automatically to delete the Variable, and ends up with a constraint violation error caused because the list of variables holded by the model still points to that variable (which by the way, I was not pretending to delete, and I've tested lots of differenst cascadeType's to avoid it without any luck...).
Thanks for your attention and be kind with my english, it's not my native language ;)
It seems you have a very interrelated model with everything referencing everything in cycles.
What are you doing exactly? When you remove the Variable, are you removing all references to it? You need to.