I am using model entities consiting of JavaFX Properties witch allows me to change the values on the single place, bind them to UI and add changed listeners with extra conditions across the array of model entities (unique values etc.).
I have to store the model in a database so the question is following:
Should I transform my model entity into JPA entity (with AccessType.PROPERTY to set the values) when I do not necessary need to all values (or all the times) to be the properties or create classic value based entity class with property based wrapper (faced) to access it.
Note: Some of the bindable properties does not have to be persisted at all.
Whether or not you should use a particular technique is very opinion-based, so I won't answer your exact question here. I will just offer some options with pros and cons.
The advantage of using JavaFX properties directly in your JPA-annotated entity class is that you keep the design simple, with just one class representing each entity, instead of wrapper classes around the entity-annotated classes.
The disadvantages to using JavaFX properties directly in the JPA entity classes are:
Potential performance cost. JavaFX properties are "heavier" than the plain data type they represent, and there is some cost in creating them and presumably in creating containers for their listeners, etc. This can be minimized (or perhaps eliminated) at the cost of some verbosity, see below.
Adding a dependency on the JavaFX API. While JavaFX ships with the standard JDK from Oracle, it is not a required part of the JSE spec, and some implementations (e.g. OpenJDK) do not include it. This is probably not much of a problem in practice, but you should be aware of it.
You can minimize the cost of using JavFX properties by using the "super lazy" pattern. Here the property objects are only created if they are actually used (e.g. if you register a listener with them); otherwise a surrogate field with the same datatype is used:
#Entity
#Access(AccessType.PROPERTY)
public class Person {
private IntegerProperty age ;
private int _age ;
private StringProperty name ;
private String _name ;
private int id ;
#Id
public int getId() {
return id ;
}
public void setId(int id) {
this.id = id ;
}
public IntegerProperty ageProperty() {
if (age == null) {
age = new SimpleIntegerProperty(_age);
}
return age ;
}
public int getAge() {
if (age == null) {
return _age ;
} else {
return age.get();
}
}
public void setAge(int age) {
if (this.age == null) {
_age = age ;
} else {
this.age.set(age);
}
}
public StringProperty nameProperty() {
if (name == null) {
name = new SimpleStringProperty(_name);
}
return name ;
}
public String getName() {
if (name == null) {
return _name ;
} else {
return name.get();
}
}
public void setName(String name) {
if (this.name == null) {
_name = name ;
} else {
this.name.set(name);
}
}
}
This basically avoids (almost) any performance overhead due to using this class in a non-JavaFX environment, because the properties are not instantiated unless explicitly requested via the xxxProperty() methods. Note that calling these methods is the only way to register listeners, so if listeners are registered, the code guarantees to notify those listeners if setXxx(...) is subsequently invoked. The cost here is some code verbosity and the very minor cost of some redundant null checking (which the JVM will probably optimize for anyway).
This technique obviously doesn't get around the issue of dependency on the JavaFX API.
Another possible option is to use a plain JavaBean with a property change listener:
#Entity
public class Person {
#Id
private int id ;
private int age ;
private String name ;
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public int getAge() {
return age ;
}
public void setAge(int age) {
int oldAge = age ;
this.age = age ;
pcs.firePropertyChange("age", oldAge, age);
}
public String getName() {
return name ;
}
public void setName(String name) {
String oldName = name ;
this.name = name ;
pcs.firePropertyChange("name", oldName, name);
}
// ...
}
Now in your JavaFX Client you can do things like:
TableView<Person> contactTable = new TableView<>();
TableColumn<Person, String> nameCol = new TableView<>("Name");
nameCol.setCellValueFactory(cellData -> {
try {
return JavaBeanStringPropertyBuilder.create()
.bean(cellData.getValue())
.name("name")
.build();
} catch (Exception exc) {
return new RuntimeException(exc);
}
});
The benefits here are that your entity is completely devoid of any dependency on JavaFX. The cost is that your client code is both more verbose and lacks compile-time checking for the existence of the correct method. There is a fair amount of reflection under the hood here, so you will take some (probably minor) performance hit in the evaluation of the properties in the client code. See JavaBean wrapping with JavaFX Properties for more details on this.
I guess one other comment may be pertinent. The most common use case in which you might want to use an entity both in and out of a JavaFX context is where you have a both a web application and a stand-alone (JavaFX) client application which both access data via a web service (e.g. providing and consuming JSON). In this case you might consider keeping two sets of classes in parallel, one using JavaFX properties and one implemented as a Java bean. Since the collection of get/set methods is identical, the JSON serializer should be able to convert the same JSON representation to either form. You can keep both forms synchronized using an interface:
public interface Person {
public int getAge() ;
public void setAge(int age) ;
public String getName() ;
public void setName(String name) ;
}
With the obvious implementations
#Entity
public class PersonEntity implements Person {
private int age ;
private String name ;
#Id
private int id ;
// get/set methods omitted...
}
and
public class PersonFX implements Person {
private final StringProperty name = new SimpleStringProperty() ;
private final IntegerProperty age = new SimpleIntegerProperty() ;
public StringProperty nameProperty() {
return name ;
}
#Override
public final String getName() {
return nameProperty().get();
}
#Override
public final void setName(String name) {
nameProperty().set(name);
}
// similarly for age...
}
Now in the JavaFX client you can have a JSON engine that [de]serializes JSON to and from PersonFX instances, and on the server you have a JSON engine that [de]serializes the same JSON data to and from PersonEntity instances. Since the JSON engine will just work via calls to get/set methods, the objects essentially have the same form from its perspective. I haven't worked with serializing to/from XML data since I started working with JavaFX, so I don't know for certain the same approach would work with XML data, but I assume you could make that work too. You could even do this with Java serialized streams, by defining readObject and writeObject methods in your implementation classes, that expected the same form of data (or by using a Serialization proxy).
Related
I have a nested POJO structure defined something like this,
public class Employee {
private String id;
private Personal personal;
private Official official;
}
public class Personal {
private String fName;
private String lName;
private String address;
}
public class Official {
private boolean active;
private Salary salary;
}
public class Salary {
private double hourly;
private double monthly;
private double yearly;
}
I get updates from a service with dot annotaion on what value changed, for ex,
id change --> id=100
address change --> personal.address=123 Main Street
hourly salary change --> official.salary.hourly=100
This POJO structure could be 3-4 level deeps. I need to look for this incoming change value and update the corresponding value in POJO. What's the best way of doing it?
If you would like to create Java objects that allows you to edit fields. You can specify your object fields with the public/default/protected access modifiers. This will enable you to get and set fields such as personal.address or official.salary.hours
This approach is typically frowned upon as the object is no longer encapsulated and any calling methods are welcome to manipulate the object. If these fields are not encapsulated with getters and setters, your object is no longer a POJO.
public provides access from any anywhere.
default provides access from any package
protected provides access from package or subclass.
public class Employee {
public String id;
public Personal personal;
public Official official;
}
public class Personal {
public String fName;
public String lName;
public String address;
}
Here's a quick approach using reflection to set fields dynamically. It surely isn't and can't be clean. If I were you, I would use a scripting engine for that (assuming it's safe to do so).
private static void setValueAt(Object target, String path, String value)
throws Exception {
String[] fields = path.split("\\.");
if (fields.length > 1) {
setValueAt(readField(target, fields[0]),
path.substring(path.indexOf('.') + 1), value);
return;
}
Field f = target.getClass()
.getDeclaredField(path);
f.setAccessible(true);
f.set(target, parse(value, f.getType())); // cast or convert value first
}
//Example code for converting strings to primitives
private static Object parse(String value, Class<?> type) {
if (String.class.equals(type)) {
return value;
} else if (double.class.equals(type) || Double.class.equals(type)) {
return Long.parseLong(value);
} else if (boolean.class.equals(type) || Boolean.class.equals(type)) {
return Boolean.valueOf(value);
}
return value;// ?
}
private static Object readField(Object from, String field) throws Exception {
Field f = from.getClass()
.getDeclaredField(field);
f.setAccessible(true);
return f.get(from);
}
Just be aware that there's a lot to improve in this code (exception handling, null checks, etc.), although it seems to achieve what you're looking for (split your input on = to call setValueAt()):
Employee e = new Employee();
e.setOfficial(new Official());
e.setPersonal(new Personal());
e.getOfficial().setSalary(new Salary());
ObjectMapper mapper = new ObjectMapper();
setValueAt(e, "id", "123");
// {"id":"123","personal":{},"official":{"active":false,"salary":{"hourly":0.0,"monthly":0.0,"yearly":0.0}}}
setValueAt(e, "personal.address", "123 Main Street");
// {"id":"123","personal":{"address":"123 Main Street"},"official":{"active":false,"salary":{"hourly":0.0,"monthly":0.0,"yearly":0.0}}}
setValueAt(e, "official.salary.hourly", "100");
// {"id":"123","personal":{"address":"123 Main Street"},"official":{"active":false,"salary":{"hourly":100.0,"monthly":0.0,"yearly":0.0}}}
I have this object. I want to access email attribute only in another class so I could check if the email is valid using assert in test directory. How do I access only email attribute from Person in another class to use it later to validate the email?
public class Person {
String name;
int year;
int month;
int day;
String email;
String phonenr;
public Person(String name, int year, int month, int day, String email, String phonenr) {
this.name = name;
this.year = year;
this.month = month;
this.day = day;
this.email = email;
this.phonenr = phonenr;
}
This is the class I want to access email attribute from:
public class PersonValidator {
public static boolean email(String email){
Person onePerson = new Person();
return false;
}
}
This is test class to test if email is valid:
class PersonRegisterTest {
#Test
void checkValidEmail() {
assertTrue(PersonValidator.email("adrianJames#oslomet.no"));
assertTrue(PersonValidator.email("example#example.com"));
assertTrue(PersonValidator.email("example.example#yahoo.com"));
}
Good practice in Java is to make all fields private, and create "getters and setters", i.e. functions to get and set values. For example:
public class Person {
private String email;
public void setEmail(String email) {
this.email = email;
}
public String getEmail() {
return this.email;
}
}
This way of doing things has several advantages:
If you you decide you want to change what values are allowed in a field, you can do that using the setter method. For example, if you want to impose a minimum length on emails, you can put if (email.length() < 10) return; in your method to prevent emails shorter than 10 characters
If you decide you want to retrieve emails over the internet or some other way, you do not have to change your code.
Many tools and frameworks expect Java objects to be in this format. Notable examples include Jackson for JSON serialization, and Spring/Spring Boot, for web application development, as well as many many more.
P.S. if you are sick of writing getters and setters:
Check if your IDE has a way of automatically generating them (most of them do)
Look into a library called Lombok, it provides the #Data annotation which can generate these methods automatically at compile time. (https://projectlombok.org/)
Its better to keep your data members/variables inside the class Person as private, and you can add getters and setters method, which you can access from outside the class and using which you can access the data members/variables of your class.
You can do something like:
public class Person {
String name;
int year;
int month;
int day;
String email;
String phonenr;
public Person(String name, int year, int month, int day, String email, String phonenr) {
this.name = name;
this.year = year;
this.month = month;
this.day = day;
this.email = email;
this.phonenr = phonenr;
}
public String getEmail()
{
return this.email;
}
}
For your case I'd make the the Person.email as package private - so it can stay as it is now, and put the PersonValidator class in the same package where you have Person class.
That would make you able to pass whole Person object to validator method like:
public static boolean email(Person person) {
String email = person.email;
return false;
}
But this is very isolated and not well designed. Also, there are plenty of ways being able to call methods from one class in another. E.g. create isEmailValid method in Person class and where you could directly use the email variable when calling PersonValidator.email(email).
Many of those uncommon approaches are most likely to invalidate SOLID, clean code and some other principles (like too tight coupled classes).
Like other answers stated it's much better to keep object fields well encapsulated (i.e. using private access modifier) and later access them with get/set methods.
Then regardless if you first create Person object (e.g. parse the Person list from file and then validate if they have correct email or get request params from smth like HTTP request for new person) you could call PersonValidator.email(personObject.getEmail() or PersonValidator.email(emailParam).
The package of keeping the PersonValidator class depends only on the convention of your project.
Having the "getters/setters" methods in an object, i.e. getEmail() setEmail(String email) getName() setName(String name) is common and good convention to keep your code well designed.
It's a good practice to implement such when applicable.
Just for further reading:
Having public getter method for email field in Person class shouldn't invalidate any coding standards (not even YAGNI-You Ain't Gonna Need It), because there could be plenty of future usages (e.g. displaying it for person/client using your program).
The mentioned encapsulation term in short words, it's about keeping inner implementation of an object inside it - i.e. not making it visible by other classes.
There're situations where an object modifies its inner fields by its methods, which are not the "setters" ones, but the current field value should always be accessed with getField() method.
"Don't overdesign, but keep future growth in mind" (i'm probably not citing anyone :P ).
The further use case could be to validate more field members of a Person object, which could result in having:
class PersonValidator {
public static boolean validatePerson(Person person) {
return validEmail(person.getEmail()) &&
//other validators when needed &&
validPhone(person.getPhonenr());
}
//very hard to validate
//most likely if has just a numbers (replacing "-" before)
//and only a length check (at least 3 without country code)
public static boolean validPhone(String phone) {
return false; //
}
public static boolean validEmail(String email) {
return false;
}
}
Again, as stated in other answers, it's much better to try searching for existing validator libraries, than writing new one - REALLY, REALLY.
There're different lenths and formats of phone numbers (mostly dependend on country), check this out.
The shortest valid email address could be a#a, or " "#a, but those are local email addresses. Check this wiki or this github gist to see some strange valid examples.
And the name, it depends on country laws and they are some which probably could accept the first names such as "A" or "Ben11" and the weirdest surname in Poland is "Cyps Albo Zyps".
First add getters to you Person object/class and make the internal state of the object only accessible via the getters:
public class Person {
private final long id;
private final String name;
private final String email;
public Person(long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
public String getEmail() {
return email;
}
// Other 2 getters
}
Then build a validator that can validate email address format, or better use a library (like https://commons.apache.org/proper/commons-validator/) for that:
public final class EmailValidator {
private EmailValidator() { }
public static boolean isValidEmail(String email) {
// check if valid email and return true or fale
}
}
Call the validator by getting the email address from new person by calling the getter. The validator shouldn't have any knowlegde of the Person object.
public static void main(String[] args) {
Person newPerson = new Person(1L, "test user", "valid#hotmail.com");
if (EmailValidator.isValidEmail(newPerson.getEmail())) {
System.out.println("Valid email address");
} else {
System.out.println("Invalid email address");
}
}
This question already has answers here:
Invoking all setters within a class using reflection
(4 answers)
Closed 5 years ago.
I have a POJO object and a collection of appropriate data.
import java.util.ArrayList;
import java.util.List;
public class TestPojo {
private String name;
private String number;
private String id;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public static void main(String[] args) {
TestPojo test = new TestPojo();
List<String> sampleData = new ArrayList<>();
sampleData.add("Bob");
sampleData.add("641-613-623");
sampleData.add("id-1451");
sampleData.add("Male");
test.setName(sampleData.get(0));
test.setNumber(sampleData.get(1));
test.setId(sampleData.get(2));
test.setSex(sampleData.get(3));
}
}
My question is how can i fill my POJO object with data in a loop? Is it posible to iterate all object setters and set data from List in appropriate places? I know that reflection can help in this case.
Here is an simple example to call setters via reflection (which needs to be adjusted):
[if this is a good approach, is another question. But to answer your question:]
public static void main(String[] args) throws Exception
{
//this is only to demonstrate java reflection:
Method[] publicMethods = TestPojo.class.getMethods(); //get all public methods
TestPojo testObj = TestPojo.class.newInstance(); //when you have a default ctor (otherwise get constructors here)
for (Method aMethod : publicMethods) //iterate over methods
{
//check name and parameter-count (mabye needs some more checks...paramter types can also be checked...)
if (aMethod.getName().startsWith("set") && aMethod.getParameterCount() == 1)
{
Object[] parms = new Object[]{"test"}; //only one parm (can be multiple params)
aMethod.invoke(testObj, parms); //call setter-method here
}
}
}
You can also save all setter-methods in an list/set for later re-use...
But as others already said, you have to be careful by doing so (using reflection)!
Cheers!
You can't easily - and you shouldn't.
You see, your POJO class offers some setters. All of them have a distinct meaning. Your first mistake is that all of these fields are strings in your model:
gender is not a string. It would rather be an enum.
"number" is not a string. It should rather be int/long/double (whatever the idea behind that property is)
In other words: you premise that "input" data is represented as array/list is already flawed.
The code you have written provides almost no helpful abstractions. So - instead of worrying how to call these setter methods in some loop context - you should rather step back and improve your model.
And hint: if this is really about populating POJO objects from string input - then get your string into JSON format, and use tools such as gson or jackson to do that (reflection based) mapping for you.
"Iterating over methods" seems pretty much of a wrong idea in OO programming. You could simply add a constructor to your class setting all of your attributes, and then just call that constructor in a loop as desired to create new objects with data you desire.
In your class define:
public TestPojo(String name, String number, String id, String sex){
this.name = name;
this.number = number;
this.id = id;
this.sex = sex;
}
Also using a List makes no much sense here. I'd recommend using a HashMap to then iterate over it in a for loop making proper calls of the above constructor.
Using the metawidget to build some flexible UI in Java: https://sourceforge.net/projects/metawidget/
public class Cohort {
private int id;
private Project project;
private Member teamLead;
public Cohort() { }
#UiHidden
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public Project getProject() { return project; }
public void setProject(Project project) { this.project = project; }
public Member getTeamLead() { return teamLead; }
public void setTeamLead(Member teamLead) { this.teamLead = teamLead; }
}
Cohort is the class inspected. However as is desirable it recursively inspects both the Project and Member classes.
When displayed on the UI, it will display all the fields for each of the classes. However I would only like to display the "Name" field of the Project and firstName + last Name of the Member.
There are a number of ways to achieve this. I'll start with one and let me know if it's sufficient for your needs:
a) mark the fields of Project/Member that you don't want to see as UiHidden (you don't say what those fields are, but you seem to have gotten the idea because you are already hiding 'Cohort.getId'). Note you can also reuse existing annotations (like JPA annotations) for this purpose.
b) mark 'Cohort.getProject' and 'Cohort.getTeamLead' as UiLabel( "" ). This will suppress the sub-label for the sub-object, and make its fields appear as if part of the original object.
While following DDD concept I'm struggling on decision if I should make my domain localization aware? I came with two two solutions how to solve this. Both makes domain localization aware in different places. Should I even place localized text to domain? Share your solution for this problem or pros and cons of my two examples. Thanks.
Example 1
class Persion {
String name;
// other fields ommited
void rename(String newName) {
String oldName = this.name;
this.name = newName
// publish event with old name and new name
}
String name() {
return name;
}
}
class PersionRepository {
void store(Persion persion) {
Locale loc = LocaleContextHolder.get().getLocale();
// store object to DAO - create/update fields for context locale
}
// other methods ommited
}
Example 2
class Persion {
Map<Locale, String> name;
// other fields ommited
void rename(String newName) {
Locale locale = LocaleContextHolder.get().getLocale();
String oldName = this.name.put(locale, newName);
// publish event with old name and new name
}
String name() {
Locale locale = LocaleContextHolder.get().getLocale();
return this.name.get(locale);
}
}
class PersionRepository {
void store(Persion persion) {
// store object to DAO - create/update fields for all locales
}
// other methods ommited
}
In most of cases, the best option is to remove localization from the domain.
Domain classes should only contain data that are relevant to their invariants, since they are responsible for business rules. To retrieve localized descriptions, use projective DTOs and applicative services.
You could use something like this:
public final class VatCode {
private final String _code;
public VatCode(String code)
{
// VAT code validation here...
_code = code;
}
#Override
public String toString() {
return _code;
}
#Override
public boolean equals(Object obj) {
// ...
}
#Override
public int hashCode() {
// ...
}
}
public class Person {
private final VatCode _identifier;
public Person(VatCode identifier)
{
_identifier = identifier;
}
// some command and some query here...
}
public class PersonDTO {
private final String _vatCode;
private final String _personalDescription;
public PersonDTO(String _vatCode, String _personalDescription) {
this._vatCode = _vatCode;
this._personalDescription = _personalDescription;
}
// other fields here...
public String getVatCode()
{
return _vatCode;
}
public String getPersonalDescription()
{
return _personalDescription;
}
// some more getter here
}
public interface LocalizedPersonalInformationService {
PersonDTO getInformationOf(VatCode person, Locale localization) throws ProperExceptionList;
}
That is:
something like a VatCode valueobject (that overrides equals, hashCode and toString) to identify the Person entity
a Person entity, holding the minimum amount of data required to ensure business invariants and exposing a set of command and queries
a PersonDTO that carries useful descriptions (some call this a read-model)
a LocalizedPersonalInformationService that is able to provide PersonDTOs.
and (obviously) all the needed exceptions... :-)
If at all possible put all your localization in the UI layer. Sometimes people find that difficult to do. For example, I worked on a project where the business logic would throw an exception and that exception would get displayed in the UI. To localize the exception we had to do something like the following (details omitted for brevity, also we had to have a LocalizedRuntimeException and a LocalizedException):
//====ArbitraryBusinessLogic.java====
if(badThing) {
throw new SubclassOfLocalizedException(LocalizedStrings.ERROR_FOO,param1,param2);
}
//====LocalizedException.java====
public class LocalizedException extends Exception {
private LocalizationKey localizationKey;
Object [] params;
public LocalizedException(LocalizationKey localizationKey, Object ... params) {
super();
localizationKey = localizationKey
params = params;
}
public String getLocalizedMessage(Locale locale) {
//message would be something like "The %s foo'd the %s"
//or of course "le %s foo'd le %s" (FYI: I don't speak French)
String message = getLocalizedMessageForKey(localizationKey);
return String.format(locale,message,params);
}
public String getLocalizedMessage() {
return getLocalizedMessage(getDefaultLocale());
}
public String getMessage() {
return getLocalizedMessage();
}
}