I have two immutable classes: User and Department, they are connected using a bidirectional association - User has a reference to Department and Department has a list of Users. How to create a new Department instance with the provided Users?
Code:
class User {
private final Department department;
private final String name;
public User(Department department, String name) {
this.department = department;
this.name = name;
}
}
class Department {
private final List<User> users;
private final String name;
public Department(List<User> users, String name) {
this.users = new ArrayList<>(users);
this.name = name;
}
}
I feel in you case you can slightly modify your design and use special UsersBuilder, i.e.
class Department {
final List<User> users;
final String name;
public Department(String name) {
this.users = UsersBuilder.buildUsers(this);
this.name = name;
}
}
class UsersBuilder {
public static List<User> buildUsers(Department department) {
List<User> usersList = new ArrayList<>();
// add users to the list via department reference
return Collections.unmodifiableList(usersList);
}
}
In general, it is not really good idea to use object's reference before its constructor finishes; but in this particular case it looks safe.
In this case these objects will be really immutable.
You can produce immutable Departments and Users with an extra constructor on Department. From the questions' code, it is inferred that
A User object is just an association between a String and a Department
User references can't exist without a Department reference.
Since Users are truly just Strings associated to a Department, a Department can be constructed with a List<String> that represents all User names to be included and use that List<String> to create a List<User> within the Department constructor.
Note: what #andremoniy said about letting this escape from a constructor should not be made a habit of, but it is safe in this case since it is only being passed to a User instance's constructor where that User instance can't be accessed before the Department constructor returns.
Here's what it would look like, in Java 8:
public final class User {
private final Department department;
private final String name;
public User(Department department, String name) {
this.department = department;
this.name = name;
}
public Department getDepartment() {
return department;
}
public String getName() {
return name;
}
}
public final class Department {
private final List<User> users;
private final String name;
///Reversed argument list to avoid collision after erasure
public Department(String name, List<String> users) {
this.users = Collections.unmodifiableList(users.stream()
.map((s) -> new User(this,s)).collect(Collectors.toList()));
this.name = name;
}
public Department(List<User> users, String name) {
this.users = Collections.unmodifiableList(users);
this.name = name;
}
public List<User> getUsers() {
return users;
}
public String getName() {
return name;
}
}
One issue this solution has is that once a Department instance is created, it can be added to new instances of User without the constraint that a new instance of Department be created with an updated List. Consider other abstractions or creational patterns (a full blown Builder implementation where all constructors are private would be a good match here) if you need to support the addition/deletion of users from a Department while maintaining immutability.
Instantiate Department with empty list of users. Then use the Department to instantiate User and add the user instance to the Department's users list.
One approach is to slightly alter what you understand immutable to mean. In object oriented design it is conventional to distinguish between the attributes of an object and its associations. Associated objects are different entities to which the object has references. If you relax the definition of immutable to mean that the attributes of the object do not change, but allow the associations to change, you avoid this kind of problem.
In your case, User and Department objects would be associated with each other, and each would have a name attribute.
I think this is a matter of modeling as well. This is ok to think that an User has a Department and a Department have Users, but the question is how deep can you look into data from User and Department ends?
Does it make sense unless conceptually you to access user.department.user[2].name? What about department.user[10].addresses[1].street?
I really don't think so on most scenarios. It's a matter of information domain. You have bondaries while accessing data and this can also be expressed somehow into your models.
If Object Modeling kind represents the real world, this is ok to think that when you go to a department, you will see dozens of people working there and most likely all you will be able to know about them is the counting and the their names perhaps. So what slices of data you should be able to see from your object?
My approach for this is:
interface PersonInfo {
String name();
String lastName();
default fullName() { return name() + " " + lastName(); }
static PersonInfoBuilder personInfo() { return new PersonInfoBuilder(); }
static class PersonInfoBuilder {
...
}
}
interface Person extends PersonInfo {
DepartmentInfo department();
Set<Address> addresses();
//...
}
interface DepartmentInfo {
String name();
String building();
// builder ...
}
interface Department extends DepartmentInfo {
Set<PersonInfo> employees();
// ...
}
I don't think i'd need to show how the builders would work since if you noticed, for this scenario, the bidirectional nature of relationship is never there. So when you build a Person, all you need is the DepartmentInfo (department no employees not required), and the same is valid when you build a Department, when all you need to have is the PersonInfo from department's employees.
That's my way to think this problem conceptually. Any comments?
My solution is to: split one of the immutable classes into two classes: a class with the attributes and a class with the bidirectional association:
class Department {
private final String name;
public Department(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class User {
private final Department department;
private final String name;
public User(Department department, String name) {
this.department = department;
this.name = name;
}
}
class DepartmentWithUsers {
private final List<User> users;
private final Department department;
public DepartmentWithUsers(Department department, List<User> users) {
this.department = department;
this.users = new ArrayList<>(users);
}
}
So to create a new user and a department instance you have to:
create a new Department instance
create a new User instance and pass the created Department instance
create a new DepartmentWithUsers instance and pass the created User instance
Related
I am having two classes:
1]BaseCustomer.java
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Builder(builderMethodName="BaseBuilder")
public class BaseCusmtomer {
private String cutomerId;
private String age;
#Default
private Boolean isActive= true;
#Default
private String type = "XYZ";
}
2] Customer.java
#Builder
public class Customer extends BaseCustomer{
private Customer(String cutomerId, String age, Boolean isActive, String type){
super(customerId,age,isActive,type);
}
}
3]Test Object
Customer.builder().cutomerId("1").age("23").build();
ut while creating object using Customer builder it always take values of isActive and type as null, it should take default values from superclass. Is there anyway to do this?
Tried to call Child builder with default parent class values
but getting null values instead of default value.
Note: can't use Superbuilder as it is experimental feature.
Since using #SuperBuilder is not an option for you, there is not much to do. One option is to create BaseCustomer "copy" constructor and create Customer by passing BaseCustomer to copy . Like this:
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Builder(builderMethodName = "BaseBuilder")
public class BaseCustomer {
protected String customerId;
protected String age;
#Default
protected Boolean isActive = true;
#Default
protected String type = "XYZ";
public BaseCustomer(BaseCustomer base) {
this.customerId = base.customerId;
this.age = base.getAge();
this.isActive = base.isActive;
this.type = base.type;
}
}
#Data
public class Customer extends BaseCustomer {
String name;
#Builder
private Customer(BaseCustomer base, String name) {
super(base);
this.name = name;
}
}
So as can be seen above, I marked Customer constructor with BaseCustomer parameter as #Builder. I added new parameter to Customer to see how it will work with additional fields. Now we can create Customer by building BaseCustomer first and then pass it with additional fields. For example:
Customer c2 = Customer.builder().base(BaseCustomer.BaseBuilder().customerId("1").age("23").build()).name("Name").build();
System.out.println(c2.getAge());
System.out.println(c2.getCustomerId());
System.out.println(c2.getType());
System.out.println(c2.getIsActive());
System.out.println(c2.getName());
This will print:
23
1
XYZ
true
Name
This has some advantages - you only pass single parameter (for base class) to Customer constructor and Customer constructor does not have to be changed for BaseCustomer field changes.
How to implement One-to-one unidirectional association in Java (without ORM). I think bidirectional is possible. Association means both classes (say Part and PartNumber) need to exist independently, one to one means only one part number for one part and vice versa, unidirectional means part should know about part number but opposite. Now how Part number will know whether it has been assigned already. If we sacrifice independent existence of PartNumber then its composition.
You could implement this as either a unidirectional or a bidirectional association. Either will work. Ensuring that the 1-to-1 property is invariant maintained can be done in various ways:
In the bidirectional case, have the setters use the forward or reverse link to ensure that the object at the other end is not already related, and maybe break that relationship.
In the unidirectional case, by removing the ability to set a Part's PartNumber or a PartNumber's Part; e.g. have the Part create its own PartNumber in its constructor.
Another alternative is to make PartNumber a "value-based class", and always use PartNumber.equals(Object) to test for equality.
I found an implementation here: http://programmersthing.blogspot.in/2017/06/java-concepts.html
1.Customer Class :
import java.util.ArrayList;
public class Customer {
private String name;
ArrayList<Order> orders = new ArrayList<Order>();
public Customer(String name) {
this.name = name;
}
public String getName() {
return name;
}
public ArrayList<Order> getOrders() {
return orders;
}
public void addOrder(Order order) {
orders.add(order);
}
}
2.LineItem Class :
public class LineItem {
private int quantity;
Product products;
public LineItem(int quantity, Product products) {
this.quantity = quantity;
this.products = products;
}
public double calculateLineItemCost() {
return (quantity * products.calculatePriceAfterDiscount());
}
public int getQuantity() {
return quantity;
}
public Product getProducts() {
return products;
}
}
I have a Role node that contains some privileges that I am trying to persist into Neo4j. When I construct the object, I see that the privileges exist, but after the save call they disappear.
Here's my Role Node:
#NodeEntity
public class Role {
#GraphId Long id;
private RoleType roleType;
//#RelatedToVia(type="HAS_ROLE", direction=Direction.OUTGOING)
private List<Person> users;
private List<Privilege> defaultPrivileges;
//private List<Task> tasks;
public Role(){}
public Role(RoleType roleType){
this.roleType=roleType;
this.defaultPrivileges=roleType.getDefaultPrivileges();
}
}
Here's my save:
admin= roleRepository.save(admin);
Before I save the object it is fully populate and after it's empty. Any ideas as to why that might be
EDIT:
The code causing the issue is in my Privilege class.
This does not work:
public class Privilege {
private String name;
public Privilege(PrivilegeType pt) {
this.name = pt.name();
}
}
This works:
public class Privilege {
private String name;
public Privilege(String pt) {
this.name = pt;
}
}
Why would that be causing it to not persist? What am I missing in my RoleRepository?
It reloads the entity after storing it, and by default it only loads a shallow copy of related information.
you can use template.fetch(role.users) or template.fetch(role.tasks)
or add #Fetch to the tasks list for instance.
I have two classes Person and Company, where the associations specify like:
(1) person work for a company
(2) person(boss) manages person(worker) by rating.
Details is provided in this image:
In case of first association i did this:
class Person {
Company co;
String name, ssn, addr;
}
class Company {
String name, addr;
}
class WorksFor {
Person person;
Company com;
int sal;
String title;
}
Is it correct implementation? also i am confused about second association. Please help me with your valuable advise.
It is not.
You should know that if class have associetion with something it is like it has attribute that type with given cardinality.
So for example Person would have given fields (omitting association classes):
String name[1]
String ssn[1]
String addr[1]
Company company[1]
Person boss[0..*]
Person worker[1..*]
Then how to change those to java:
String name;
String ssn;
String addr;
Company company;
List<Person> bosses;
List<Person> worker;
But remember if there is required number of given type you should pass those elements in constructor.
One thing important to mention: if in UML value is omitted it means [1].
So we need to have constructor that takes worker as argument.
With association classes things getting more complicated:
You should create classeslike
class Performance {
Person boss;
Person worker;
int performanceRating;
public Performance(Person boss, Person worker, int performanceRating){
this.boss = boss;
this.worker = worker;
this.performanceRating = performanceRating;
}
}
And in person change those list of Persons to list of Performance.
Still it's invalid UML diagram so I'm not perfectly sure if my answer can helps.
Usually, class in model (classes associated with data) is related with real-world objects. And it is common practice to call classes with a noun, so I would change WorksFor into something else.
class Person {
String name, ssn, addr;
Job job;
Person boss;
}
class Company {
String name, addr;
}
class Job {
Company co;
int salary;
String title;
}
The problem with code above is ratings and obtaining workers of the boss - it can be solved in multiple ways. Assuming, that every boss is also a worker, you can extend a Person class:
class Boss extends Person {
List<Person> workers;
}
Another possibility is keeping list of workers with Person - list will be empty/null if a person is not a boss.
Some ideas of performance management is given in KonradOliwer answer, I'm not going to duplicate it.
Could do like this:
class Person {
EmploymentRelationship employmentRelationship;
List<ManagementRelationship> workerManagementRelationships;
ManagementRelationship bossManagementRelationship;
String name, ssn, addr;
}
class Company {
String name, addr;
}
class EmploymentRelationship {
Person person;
Company com;
int sal;
String title;
}
class ManagementRelationship {
int performanceRating;
Person boss;
Person worker;
}
I have a pojo that is dependent on annotations. It has predefined fields as well as a Set that contains user provided fields:
public class MyPOJO implements Document {
private String id;
private LocalString name;
private LocalString desc;
private List<Field> fields;
public MyPOJO(final String id,
final LocalString name,
final LocalString desc,
final List<Field> fields) {
this.id = id;
this.name = name;
this.desc = desc;
this.fields = fields;
}
public String getId() {
return id;
}
#Indexed(searchable = false, stored = true)
public LocalString getName() {
return name;
}
#Indexed(searchable = true)
public LocalString getDescription() {
return desc;
}
public List<Field> getFields() {
return fields;
}
}
MyPOJO is a 'generic' object, ie, the developer (or consumer) of MyPOJO has fields that are not predefined in MyPOJO and therefore the developer needs to place these additional fields the in attribute 'fields'. The problem arises from the fact that each object in the Set fields needs to have its own annotations to indicate whether the particular field is either stored or searchable in order to remain consistent with the predefined attributes, such as name.
I can think of two options:
For each additional field, the developer will have to create an
anonymous class implementing the interface Field and inside this
anonymous class, the developer will declare the applicable
annotations.
the Set 'fields' contains a complex object of fieldname, fieldvalue
and annotations as shown below. I can't figure out how to invoke the constructor for Field. The below code does not compile but it is intended as pseudo-code to signify what I am trying to do.
Field myfield1 = new Field("dateofBirth", new Date(), new ArrayList({Index.stored, Index.searchable});
Field myfield2 = new Field("model", "330i", new ArrayList({Index.stored});
There is no construct to pass annotations as a parameter: new ArrayList({Index.stored}.
public class Field {
private String name;
private Object value;
Collection<Annotation> annotations;
public Field(final String name, final Object value, Collection<Annotation> annotations;) {
this.name = name;
this.value = value;
this.annotations = Collections.unmodifiableCollection(annotations);
}
public String getName() {
return name;
}
public Object getValue() {
return value;
}
}
I'm not particularly excited with either option and hoping someone can give me some pointers
If you need an extensible object model, I'd say a POJO design is just setting yourself up for extra work as opposed to exposing a metamodel.
That said, what you could do is have clients of the API subclass MyPOJO, and annotate the properties they define in their subclasses. You would then use reflection to go through all JavaBeans properties of the objects you're receiving and determine the annotations on the getters - similarly to how JPA works.