ArrayList of enums with custom attribute - java

I have enum class that describes possible tickets types and have custom atribute to keep ticketId. When I try to add some tickets to ArrayList it makes all tickets of type X have the same ticketId. Why is that and what's more important how can I solve it?
Simplified enum class:
public enum Ticket {
FirstClass(0),
PremiumClass(1),
EconomyClass(2);
private int elementId;
private Long ticketId;
Ticket(int elementId) {
this.elementId=elementId;
}
public Long getTicketId() {
return ticketId;
}
public void setTicketId(Long ticketId) {
this.ticketId = ticketId;
}
}
Simplified method:
public void myMethod() {
ArrayList<Ticket> tickets = new ArrayList<>();
Ticket ticket = Ticket.FirstClass;
ticket.setTicketId(1L);
tickets.add(ticket);
ticket = Ticket.FirstClass;
ticket.setTicketId(2L);
tickets.add(ticket);
}

It is happening because there is only one instance for every enum constant. Calling Ticket.FirstClass will fetch the same instance every time. So you are adding the same object to the list twice.

There is really only one instance of Ticket.FirstClass, and there will only ever be one instance.
What you really have isn't a Ticket, but a TicketType. You should have a separate class for Ticket.

FirstClass is an instance of Ticket so when you're calling it, it's always the same one, you take the reference to the same object.
What you would need is a model with a Ticket and a TicketType
enum TicketType {
FirstClass,
PremiumClass,
EconomyClass
}
class Ticket {
private TicketType type;
private Long ticketId;
Ticket(TicketType type, long ticketId) {
this.type = type;
this.ticketId = ticketId;
}
}
// ---------------------------------------------------------
// And
public void myMethod() {
ArrayList<Ticket> tickets = new ArrayList<>();
Ticket ticket = new Ticket(TicketType.FirstClass, 1L);
tickets.add(ticket);
ticket = new Ticket(TicketType.FirstClass, 2L);
tickets.add(ticket);
}

Don't use enums for dynamic values,see sonar's "enum" fields should not be publicly mutable
enums are generally thought of as constant, but an enum with a public field or public setter is not only non-constant, but also vulnerable to malicious code.
See example of making enum dynamic by making it implement an interface

Nothing different from other answers, just to add some colors.
When you obtain firstClass you actually are getting same object, and adding that again.

Each enum value (you have got three) exists only once and each time you are using one of them you are just reusing one of those three values by creating a reference, there are no copies.
This means if you change the ticketId on the FirstClass value, it is changed wherever that value is referenced.
It seems you want to model a little ticket system. Each object having an own identity should be modeled as a class which has a property for the type and the id:
public class Ticket {
private Long ticketId;
private TicketType type;
public Long getTicketId() {
return ticketId;
}
public void setTicketId(Long ticketId) {
this.ticketId = ticketId;
}
public TicketType getType() {
return type;
}
public void setType(TicketType type) {
this.type = type;
}
}
public enum TicketType {
FirstClass(0),
PremiumClass(1),
EconomyClass(2);
private final int elementId;
Ticket(int elementId) {
this.elementId = elementId;
}
public int getElementId() {
return elementId;
}
}
Then you can use it this way:
public void myMethod() {
ArrayList<Ticket> tickets = new ArrayList<>();
Ticket ticket = new Ticket();
ticket.setType(TicketType.FirstClass);
ticket.setTicketId(1L);
tickets.add(ticket);
ticket = new Ticket();
ticket.setType(TicketType.FirstClass);
ticket.setTicketId(2L);
tickets.add(ticket);
}
I don't know why you need an elementId on the ticket type, that's why I just left it there (without using it). Probably you should rename ticketId to just id to keep it simple.
If the ticket's type or ticketId are never changed after assigning them you may want to remove the setters and assign the values in the constructor of Ticket (and make the attributes final).
Even if it's ok that they are changeable, you may introduce such a constructor to have code which is better readable:
In Ticket.java:
public Ticket(Long ticketId, TicketType type) {
this.ticketId = ticketId;
this.type = type;
}
Then you can write:
tickets.add(new Ticket(1L, TicketType.FirstClass));
If ticket is a persisted entity (which gets inspected by a framework like Hibernate) you might have to keep a no-args constructor to make it instantiable when loading it from a database.

Related

Java nested POJO update based on dot annotation

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}}}

update an existing object in list

Q: I have a Bank class containing multiple loan accounts (LoanAccount class). I've create a LoanAccountService that have the CRUD functionalities. My concerns are about how I implemented the update functionality.
Bank
public class Bank {
private List<LoanAccount> loanAccounts;
}
Loan account
public class LoanAccount {
private String id;
private Integer numberOfInstallments;
private LoanAccountType type;
private Date creationDate;
private BigDecimal loanAmount;
}
Service
public class LoanAccountService{
private Bank bank;
public LoanAccountService(Bank bank) {
this.bank = bank;
}
public LoanAccount update(LoanAccount loanAccount) {
Optional<LoanAccount> account = bank.getLoanAccounts()
.stream()
.filter(la -> la.getId().equals(loanAccount.getId()))
.findAny();
if (account.isPresent()) {
account.get().setCreationDate(loanAccount.getCreationDate());
account.get().setLoanAmount(loanAccount.getLoanAmount());
account.get().setNumberOfInstallments(loanAccount.getNumberOfInstallments());
account.get().setType(loanAccount.getType());
} else {
throw new IllegalArgumentException("The object does not exist.");
}
return loanAccount;
}
}
When the method update is called with a LoanAccount containing an id that already exists in loanAccounts list, I want to update the existing object with the object loanAccount given as parameter.
Above is my implementation, but I feel like there should be better ways to do it.
Use Builder for getter and setter
public class LoanAccount {
private String id;
private Integer numberOfInstallments;
// add other properties
public String getId() {
return id;
}
public LoanAccount setId(String id) {
this.id = id;
return this;
}
public Integer getNumberOfInstallments() {
return numberOfInstallments;
}
public LoanAccount setNumberOfInstallments(Integer numberOfInstallments) {
this.numberOfInstallments = numberOfInstallments;
return this;
}
Use this one for update method
public LoanAccount update(LoanAccount loanAccount) {
return bank.getLoanAccounts()
.stream()
.filter(la -> la.getId().equals(loanAccount.getId()))
.findFirst().orElseThrow(IllegalArgumentException::new)
.setCreationDate(loanAccount.getCreationDate())
.setLoanAmount(loanAccount.getLoanAmount())
.setNumberOfInstallments(loanAccount.getNumberOfInstallments())
.setType(loanAccount.getType());
}
You could use a HashMap where the TKey is the type of your LoanAccount.id.
Then call loanAccounts.put(id, object)
This will update the object if there is already an Id and add a new object if not.
This is a cheap, dirty way. Another way of doing it would be to make your LoanAccount class implement Comparable and in the compareTo() method make a id based comparation.
Do the same thing overriding your equals() and you should be ready to go.
#Override
public boolean equals(object obj) {
if (obj == null) return false;
return ((LoanAccount)obj).getId() == this.getId();
}
something like that.
(code wrote by memory, can have errors and lacks validations like the data type)
What kind of persistence layer do you use?
why do you need to loop through all of the bank accounts?
Did you fetch all the accounts from the repository and loop over the service layer? If so why?
why not you fetch the corresponding single record from repository and update?
Why not you use to find and update the records instead of using the above points?
These questions may give you an idea. If you answering it !!!
If not let we discuss deeper

What's more efficient: Class object or Object[] (object array)?

I'm not sure if a class object to transfer data will be more efficient than an object array.
My goal is to know which option is the most efficient and which option is the best practice.
Consider this is a web application served to thousands of users.
Here the two sample cases:
A)
Model.java
public class Model {
public Contact getContact(long id)
{
// some logic
return new Contact(...);
}
}
Contact.java
public class Contact
{
private long id;
private String name;
private String surname;
private String email;
private int session;
private byte[] avatar;
// Constructor
public Contact(long id, String name, ...)
// Getters and Setters
}
B)
Model.java
public class Model {
public Object[] getContact(long id)
{
// some logic
Object[] myReturningContact = new Object[n];
myReturningContact[0] = rs.getLong("id");
// ...
myReturningContact[n] = rs.getBytes("avatar");
return myReturningContact;
}
}
SomeController.java
public class SomeController
{
public void someAction()
{
// Option A
this.setSomeTextTo(contact.getName());
// Option B
this.setSomeTextTo(String.valueOf(returningObject[n]));
}
}
Option A is best practice, unless you have a speed requirement that it can't meet, and Option B can.
Note that Option A will probably be a little faster if you make your fields public and final and don't use getters.
Also note that if you have many primitive fields, the cost of boxing and unboxing will slow down Option B, as may String.valueOf on Strings

Using reflection to get a specific attribute from a extended instance

I would like to make a generic method to get a List from the parameter object.
The problem is because I have a declared object with a instance of the other class that extends the declared class.
I don't want to use the instanceof solution because the number of classes that extends LimitedValue can be big.
I thought to use reflection for a solution, but I don't know how to use that with an instance of object, in this part of the code:
Class cls = Class.forName(limitedValue.getClass().getName());
Object obj = cls.newInstance();
//This is wrong, I don't want a new instance.
Method[] methods = cls.getDeclaredMethods();
for(int x= 0; x < methods.length; x++) {
Method method = methods[x];
if ("java.util.List".equals(method.getReturnType().getName())) {
//How to get the value of this method from limitedValue instance ?
}
}
This is my full code:
public class CalculatorLimitedValue {
public static void main(String[] args) throws Exception {
StoreItem storeItem = new StoreItem(1L, "Name of StoreItem", 50L);
List listOfStoreItems = new ArrayList();
listOfStoreItems.add(storeItem);
LimitedValue limitedValue0 = new Store(listOfStoreItems);
List firstList = calculator(limitedValue0);
//do something with the list
SupermarketItem supermarketItem = new SupermarketItem(1L, "Name of SupermarketItem", 21L);
List listOfSupermarketItems = new ArrayList();
listOfSupermarketItems.add(supermarketItem);
LimitedValue limitedValue1 = new Supermarket(listOfSupermarketItems);
List secondList = calculator(limitedValue1);
//do something with the list
}
/** This is the method that I'd like to make generic to return a List */
private static List calculator(LimitedValue limitedValue) throws Exception{
Class cls = Class.forName(limitedValue.getClass().getName());
Object obj = cls.newInstance();
//This is wrong, I don't want a new instance.
Method[] methods = cls.getDeclaredMethods();
for(int x= 0; x < methods.length; x++) {
Method method = methods[x];
if ("java.util.List".equals(method.getReturnType().getName())) {
//How to get the value of this method from limitedValue instance ?
}
}
/* I don't want to use this one way, because my classes that extends LimitedValue
can be big. I would like to made a generic way to get de list of classes. */
if (limitedValue instanceof Store) {
System.out.println("This is a store");
return ((Store) limitedValue).getStoreItems();
} else if (limitedValue instanceof Supermarket) {
System.out.println("This is a supermarket");
return ((Supermarket) limitedValue).getSupermarketItems();
}
return null;
}
}
If it help, these are my other classes:
LimitedValue.class
public class LimitedValue { }
StoreItem.class
public class StoreItem {
private Long id;
private String nameOfStoreItem;
private Long valueOfStoreItem;
public StoreItem(Long id, String nameOfStoreItem, Long valueOfStoreItem){
this.id = id;
this.nameOfStoreItem = nameOfStoreItem;
this.valueOfStoreItem = valueOfStoreItem;
}
//getters and setters...
}
SupermarketItem.class
public class SupermarketItem {
private Long id;
private String nameOfSupermarketItem;
private Long valueOfSupermarketItem;
public SupermarketItem() {
}
public SupermarketItem(Long id, String nameOfSupermarketItem, Long valueOfSupermarketItem) {
this.id = id;
this.nameOfSupermarketItem = nameOfSupermarketItem;
this.valueOfSupermarketItem = valueOfSupermarketItem;
}
//getters and setters...
}
Store.class
public class Store extends LimitedValue {
private List<StoreItem> storeItems;
public Store(List<StoreItem> storeItems) {
this.storeItems = storeItems;
}
//getters and setters
}
Supermarket.class
public class Supermarket extends LimitedValue {
private List<SupermarketItem> supermarketItems;
public Supermarket(List<SupermarketItem> supermarketItems) {
this.supermarketItems = supermarketItems;
}
//getters and setters
}
You could try to use reflection here to try to achieve what you want, but it would be better to reconsider your overall design and try to use a better object oriented design that solves the problem at hand.
In particular, lets say we consider adding a method called getItems to the LimitedValue class that returns a List of items, which may be SupermarketItems or may be StoreItems. If it is structured correctly, you won't need to know the actual type because the code will be abstracted over it polymorphically.
public abstract class LimitedValue {
List<? extends Item> getItems();
}
We've now defined a new method on LimitedValue, but we also have to consider that we've introduced this new Item thing. I note that the SupermarketItem and StoreItem all share similiar attributes, name, id and value, so it seems that it might be possible to use a single class to represent them all.
public abstract class Item {
final Long id;
final String name;
final Long value;
public Item(final Long id, final Long name, final Long value) {
this.id = id;
this.name = name;
this.value = value;
}
String getName() {
return name;
}
// other getters and setters
}
public class SupermarketItem extends Item {
public SupermarketItem(final Long id, final Long name, final Long value) {
super(id, name, value);
}
}
public class StoreItem extends Item {
public StoreItem(final Long id, final Long name, final Long value) {
super(id, name, value);
}
}
Now we've completely abstracted away the need for any reflection when accessing these objects - you can simply call item.getValue() as you will know that every item in the list is of type Item.
Of course, you'll also need to refactor the Store and SuperMarket classes, for example:
public class Supermarket extends LimitedValue {
private List<SupermarketItem> supermarketItems;
public Supermarket(List<SupermarketItem> supermarketItems) {
this.supermarketItems = supermarketItems;
}
public List<? extends Item> getItems() {
return supermarketItems;
}
}
and because you are only returning a List<Item> you always know what is in it, and you can change your main code to work with this.
This is a much cleaner long term solution.
To get the List value, use Method#invoke:
List list = method.invoke(limitedValue);
You don't need Object obj = cls.newInstance(); - you're not using it at all in the method.
In any case, you're making it very difficult for yourself. You could also define an interface
public interface HasList<E> {
List<E> getList();
}
and have all classes implement this.

Only Allow Objects with Unique Name - Java

I am making an inventory system.
I want to ensure that objects I am creating (Ingredients) all have unique names. In other words, I want to make sure that there are never two Ingredients that have the same name in the whole program. Currently I have the following class:
package ingredient;
import java.util.HashSet;
public class Ingredient {
private final String name;
private final double price;
private static HashSet<String> names = new HashSet<String> ();
private Ingredient(String ingr_name, double ingr_price) {
name = ingr_name;
price = ingr_price;
}
public static Ingredient createIngredient(String ingr_name, double ingr_price) {
if (names.contains(ingr_name)) {
return null;
} else {
names.add(ingr_name);
return new Ingredient(ingr_name, ingr_price);
}
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
}
Then, when I go to actually make new ingredients, I make statements such as :
Ingredient egg = Ingredient.createIngredient("egg", 1);
Is this okay design? I suppose I am concerned because returning "NULL" might not be the best practice here.
I cant comment, but whatever...
I would go about this by storing all of the Ingredients in a different class, then you wouldn't need all this static nonsense. In the class where you actually create a new Ingredient (Ingredient egg = Ingredient.createIngredient("egg", 1);) you could maybe create an ArrayList of ingredients like so:
ArrayList<Ingredient> ingredients = new ArrayList<>();
Then when you make a new Ingredient you would just have to make sure you add it to the ArrayListand when you do so, check that none of the ingredients are already there, maybe something like this:
createIngredient("egg", 1);
or
Ingredient egg = createIngredient("egg", 1);
...
private Ingredient createIngredient(String ingr_name, double ingr_price){
for(Ingredient i : ingredients){
if(i.getName().equals(ingr_name)){
return null;
}
}
Ingredient newing = new Ingredient(ingr_name, ingr_price);
ingredients.add(newing);
return newing;
}
Then the Ingredient class could be cut down to something like this:
package ingredient;
public class Ingredient {
private final String name;
private final double price;
public Ingredient(String ingr_name, double ingr_price) {
name = ingr_name;
price = ingr_price;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
}
And then you could access each individual Ingredientwith a method to run through the ArrayList and find the Ingredient with the name your looking for:
public Ingredient findIngredient(String name){
for(Ingredient i : ingredients){
if(i.getName().equals(name)){
return i;
}
}
return null;
}
I would recommend either
A) returning the already created ingredient
Or if that would confuse the caller,
B) throwing an exception
This can be a simple IllegalArgumentsException, or depending on your needs, a custom exception class.

Categories

Resources