How to custom string setters to uppercase with Lombok? [duplicate] - java

I would like to understand how to create a custom setter in Lombok and apply the setter on specific member. I have a class with 100 members, and for 50 of them I have a custom setter that check something X before I set the value, and another 50 that have a custom setter that check something Y before the I set the value. Can it be done?
this is a exmple ,
2 members 2 diffrent setters ,
this code is repeated for all members in my class :
#JsonProperty("TAC_LAC_Start_UE1")
private Integer tacLacStartUe1;
#JsonProperty("TAC_LAC_Start_UE2")
private Integer tacLacStartUe2;
#Override
public void setTacLacStartUe1(Integer tacLacStartUe1) {
if (Objects.equals(getTacLacStartUe1(), tacLacStartUe1)) {
return;
}
this.tacLacStartUe1 = tacLacStartUe1;
if (DocKind.ORIG == docKind) {
((EventDocument) prepareDirtyDocument()).setTacLacStartUe1(tacLacStartUe1);
}
}
#Override
public Integer getTacLacStartUe2() {
return tacLacStartUe2;
}
#Override
public void setTacLacStartUe2(Integer tacLacStartUe2) {
if (Objects.equals(getTacLacStartUe2(), tacLacStartUe2)) {
return;
}
this.tacLacStartUe2 = tacLacStartUe2;
if (DocKind.ORIG == docKind) {
((EventDocument) prepareDirtyDocument()).setTacLacStartUe2(tacLacStartUe2);
}
}

Based on the current version's documentation (https://projectlombok.org/features/GetterSetter), it doesn't seem to include a way to specify custom checks for the setter (or getter). I fear you will have to manually code each and every setter.
The same applies for the experimental #Accessor feature.

As #Laf said, Lombok doesn't currently support this feature. However, you still can get rid of some duplicated code by extracting setters logic to the following higher-order function:
private void doSetTacLacStartUe(
Integer oldValue,
Integer newValue,
Consumer<Integer> setter,
BiConsumer<EventDocument, Integer> eventDocumentUpdater
) {
if (Objects.equals(oldValue, newValue)) return;
setter.accept(newValue);
if (DocKind.ORIG == docKind)
eventDocumentUpdater.accept((EventDocument) prepareDirtyDocument(), newValue);
}
And using it this way:
public void setTacLacStartUe1(Integer tacLacStartUe1) {
doSetTacLacStartUe(getTacLacStartUe1(), tacLacStartUe1, it -> this.tacLacStartUe1 = it, EventDocument::setTacLacStartUe1);
}

Related

Using Lombok library, but how to customize/override the setter method [duplicate]

This question already has answers here:
How to override Lombok Setter methods
(2 answers)
Closed 2 years ago.
I use lombok library in my java project.
#Data
public class Score {
private long grade;
}
With this code, I have getter and setter automatically. e.g.
Score score = new Score();
score.setGrade(10);
// when I call score.getGrade(), I get 10.
But now I want to customize the setter method to introduce additional logics for the grade value. e.g.
public void setGrade(long grade) {
// so the returned value from getter is always 1 bigger than what has been set.
this.grade += 1;
}
Basically, I want to have score.setGrade(10) but score.getGrade() returns 11. That's override the setter.
How to achieve it with lombok in use?
You can just write the getter method in the class. Lombok will not override methods. If a method that it should generate is already present, it will skip that one.
So you could do this:
#Data
public class Score {
private long grade;
public void setGrade(long grade) {
this.grade = grade + 1;
}
}
Or instead just override the getter:
#Data
public class Score {
private long grade;
public long getGrade() {
return this.grade + 1;
}
}
Edit:
To add on your comment: #Override is only required if you override methods from superclasses or interfaces. Lombok injects the method directly into your class, thus no #Override is required (and it will cause an compiler error, because there is nothing that could be overridden).
This works fine for me
class Scratch {
public static void main(String[] args) {
MyDataClass object = new MyDataClass();
object.setOverriddenSet("some value");
if (!"fixed value".equals(object.getOverriddenSet())) {
throw new RuntimeException();
}
System.out.println("all went well.");
}
}
#Data
class MyDataClass {
String overriddenSet = "fixed initial value";
void setOverriddenSet(String setTo) {
overriddenSet = "fixed value";
}
}

Lombok - how to create custom setters and apply on different member in java

I would like to understand how to create a custom setter in Lombok and apply the setter on specific member. I have a class with 100 members, and for 50 of them I have a custom setter that check something X before I set the value, and another 50 that have a custom setter that check something Y before the I set the value. Can it be done?
this is a exmple ,
2 members 2 diffrent setters ,
this code is repeated for all members in my class :
#JsonProperty("TAC_LAC_Start_UE1")
private Integer tacLacStartUe1;
#JsonProperty("TAC_LAC_Start_UE2")
private Integer tacLacStartUe2;
#Override
public void setTacLacStartUe1(Integer tacLacStartUe1) {
if (Objects.equals(getTacLacStartUe1(), tacLacStartUe1)) {
return;
}
this.tacLacStartUe1 = tacLacStartUe1;
if (DocKind.ORIG == docKind) {
((EventDocument) prepareDirtyDocument()).setTacLacStartUe1(tacLacStartUe1);
}
}
#Override
public Integer getTacLacStartUe2() {
return tacLacStartUe2;
}
#Override
public void setTacLacStartUe2(Integer tacLacStartUe2) {
if (Objects.equals(getTacLacStartUe2(), tacLacStartUe2)) {
return;
}
this.tacLacStartUe2 = tacLacStartUe2;
if (DocKind.ORIG == docKind) {
((EventDocument) prepareDirtyDocument()).setTacLacStartUe2(tacLacStartUe2);
}
}
Based on the current version's documentation (https://projectlombok.org/features/GetterSetter), it doesn't seem to include a way to specify custom checks for the setter (or getter). I fear you will have to manually code each and every setter.
The same applies for the experimental #Accessor feature.
As #Laf said, Lombok doesn't currently support this feature. However, you still can get rid of some duplicated code by extracting setters logic to the following higher-order function:
private void doSetTacLacStartUe(
Integer oldValue,
Integer newValue,
Consumer<Integer> setter,
BiConsumer<EventDocument, Integer> eventDocumentUpdater
) {
if (Objects.equals(oldValue, newValue)) return;
setter.accept(newValue);
if (DocKind.ORIG == docKind)
eventDocumentUpdater.accept((EventDocument) prepareDirtyDocument(), newValue);
}
And using it this way:
public void setTacLacStartUe1(Integer tacLacStartUe1) {
doSetTacLacStartUe(getTacLacStartUe1(), tacLacStartUe1, it -> this.tacLacStartUe1 = it, EventDocument::setTacLacStartUe1);
}

How to get enum value from property

I have an enum with values VALID and INVALID, which have a boolean property associated with them. I would like to get the enum value based on a boolean value I provide.
If it is true I should get VALID, if it is false I should get INVALID. I would like to do so in a getter method like the below, based on the value of the member variable
public boolean getCardValidityStatus() {
return CardValidationStatus status = CardValidationStatus(this.mCardValidityStatus));
}
My code:
private enum CardValidationStatus {
VALID(true),
INVALID(false);
private boolean isValid;
CardValidationStatus(boolean isValid) {
this.isValid = isValid;
}
public boolean getValidityStatus() {
return this.isValid;
}
}
You're able to achieve that using a static lookup method in the enum itself:
private enum CardValidationStatus {
VALID(true),
INVALID(false);
//...
public static CardValidationStatus forBoolean(boolean status) {
//this is simplistic given that it's a boolean-based lookup
//but it can get complex, such as using a loop...
return status ? VALID : INVALID;
}
}
And the appropriate status can be retrieved using:
public CardValidationStatus getCardValidityStatus() {
return CardValidationStatus.forBoolean(this.mCardValidityStatus));
}
I would add a parse method to your enum, which takes the boolean, iterates over all the values and returns the one that matches, for example:
public CardValidationStatus parse(boolean isValid) {
for (CardValidationStatus cardValidationStatus : CardValidationStatus.values()) {
if (cardValidationStatus.getValidityStatus() == isValid) {
return cardValidationStatus;
}
}
throw new IllegalArgumentException();
}
#ernest_k solution made this work, but I think that's not reliable solution.
You should always do code which is independent.
Because his solution is hardcoded. What if values of VALID & INVALID are changed. Will you change your forBoolean logics also?
Because he did not check what the Enum fields are holding inside it.
Reliable solution will be #DaveyDaveDave answer. This will also work when you have many status with VALID & INVAlID.
private enum CardValidationStatus {
VALID(true),
INVALID(false);
//...
public CardValidationStatus forBoolean(boolean isValid) {
for (CardValidationStatus cardValidationStatus : CardValidationStatus.values()) {
if (cardValidationStatus.getValidityStatus() == isValid) {
return cardValidationStatus;
}
}
throw new IllegalArgumentException();
}
}
Suggestion (Easiest way I think)
Why are you making Enum just for storing 2 boolean values?
Just make static boolean named by VALID & INVALID.
public static final boolean CARD_STATUS_VALID = true;
public static final boolean CARD_STATUS_INVALID = false;
if(cardStatus == CARD_STATUS_VALID){
// todo
}

How to do refactoring to eliminate type-code if it is used in validation rules?

Let's say we have to check some set of rules before adding a new element in a collection. Elements are objects of a few similar types. All type specific features are encapsulated in subclasses of an abstract class. Collection contains objects of this abstract class. The rules apply conditions for types along with other constraints. For that reason the abstract superclass of items has additional type code. New element can be added to collection but due to additional rules other elements in collection can be removed or replaced.
In the code that needs to be refactored, validation of the rules is implemented as one long block of code with nested control flow statements. Validation of the type code breaks encapsulation. Separate branches of the control flow statements cannot be defined as method of corresponding subclasses of collection elements because them need to check type and make changes to collection.
additional facts regarding type code in my case:
type code does not affect the behaviour of class
type code is immutable
type code is used by ItemsManager to resolve some rules before to add
new element to collection.
How to eliminate type code and separate rules from types?
Here is example of such problem:
Type specific features of Items are encpsulated in AbstractItem subclasses.add method of ItemManager class breaks encapsulation.Rule: item of Type2 must be removed if new item of Type1 with the same value of SomeUsefull property is adding to collection.
For simplicity implementation of ICloneable and IComparable interfaces is omitted. In real world items in collection are immutable and cloneable and the system of rules is quite tangled.
abstract class AbstractItem {
private int Type; // this would like to eliminate
private int SomeUseful;
protected AbstractItem(int Type, int Value) {
this.Type = Type;
this.SomeUseful = Value;
}
public int getType() { return this.Type; }
public int getSomeUseful() { return this.SomeUseful; }
#Override
public String toString() {
return String.format("Item{Type=%d, Value=%d}", Type, SomeUseful);
}
}
class ItemType1 extends AbstractItem {
ItemType1(int Value) { super(1, Value); }
}
class ItemType2 extends AbstractItem {
ItemType2(int Value) { super(2, Value); }
}
class ItemManager {
private java.util.ArrayList<AbstractItem> ListOfItems;
public ItemManager(){
this.ListOfItems = new java.util.ArrayList<AbstractItem>();
}
public void add(final AbstractItem newItem) {
// this code breaks encapsulation
switch (newItem.getType()) {
case 1:
// do some type dependent operations
for(AbstractItem i: this.ListOfItems) {
if (i.getType()==2 && i.getSomeUseful()==newItem.getSomeUseful()) {
this.ListOfItems.remove(i);
break;
}
}
break;
case 2:
// do some other type dependent operations
break;
default:
// throw error
}
this.ListOfItems.add(newItem);
}
#Override
public String toString() {
String str = String.format("ItemsManager content");
for(AbstractItem i: this.ListOfItems) {
str += String.format("\n\tType = %d, Value = %d", i.getType(), i.getSomeUseful());
}
return str;
}
}
public class Example1 {
public static void main(String[] arg) {
System.out.println("Example 1");
ItemManager im = new ItemManager();
im.add(new ItemType1(1));
im.add(new ItemType2(2));
im.add(new ItemType2(3));
im.add(new ItemType1(3));
System.out.println(im.toString());
}
}
/*
Example 1
ItemsManager content
Type = 1, Value = 1
Type = 2, Value = 2
Type = 1, Value = 3
*/
Starting from #dbugger's answer you can push it further.
You can use Double Dispatch to hide the type code. Still not a perfect solution because the parent knows too much about its children, but the type code is gone now.
It is hard to tell what a better solution might be with the example code you have given, because when you simplified, you removed all the information about the items involved. There might be something there that could be used for discrimination in some other way, allowing you to get rid of the double dispatch with shoudBeRemovedBecauseType1.
Here is the altered onAdd method from type 1
#Override
public List<AbstractItem> onAdd(List<AbstractItem> list) {
for (AbstractItem item : list) {
if (item.shoudBeRemovedBecauseType1(this)) {
list.remove(item);
break;
}
}
return list;
}
A new method in the base class
public boolean shoudBeRemovedBecauseType1(ItemType1 itemType1)
{
return false;
}
overridden in the type 2 subclass
#Override
public boolean shoudBeRemovedBecauseType1(ItemType1 itemType1)
{
return getSomeUseful() == itemType1.getSomeUseful();
}
It's not ideal, but it's a step towards getting some encapsulation and killing the switch statement...
add an onAdd method to the base class that takes the list as a parameter.
public java.util.ArrayList<AbstractItem> onAdd(java.util.ArrayList<AbstractItem> list) { return list; }
then override it in the sub classes, for example...
#Override
public java.util.ArrayList<AbstractItem> onAdd(java.util.ArrayList<AbstractItem> list) {
for(AbstractItem i: this.ListOfItems) {
if (i.getType()==2 && i.getSomeUseful()==this.getSomeUseful()) {
list.remove(i);
break;
}
}
return list;
}
then rewrite the ItemManager add method to just call the sub classes' onAdd methods...
public void add(final AbstractItem newItem) {
this.ListOfItems = newItem.onAdd(this.ListOfItems);
this.ListOfItems.add(newItem);
}

List of enum vs. class of booleans

For now, I have a class with fields.
#Entity
public class Fuel {
#Id #GeneratedValue
private Long id;
private boolean diesel;
private boolean gasoline;
private boolean etanhol;
private boolean cng;
private boolean electric;
public Fuel() {
// this form used by Hibernate
}
public List<String> getDeclaredFields() {
List<String> fieldList = new ArrayList<String>();
for(Field field : Fuel.class.getDeclaredFields()){
if(!field.getName().contains("_") && !field.getName().equals("id") && !field.getName().equals("serialVersionUID") ) {
fieldList.add(field.getName());
}
Collections.sort(fieldList);
}
return fieldList;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public boolean isDiesel() {
return diesel;
}
public void setDiesel(boolean diesel) {
this.diesel = diesel;
}
public boolean isGasoline() {
return gasoline;
}
public void setGasoline(boolean gasoline) {
this.gasoline = gasoline;
}
public boolean isEtanhol() {
return etanhol;
}
public void setEtanhol(boolean etanhol) {
this.etanhol = etanhol;
}
public boolean isCng() {
return cng;
}
public void setCng(boolean cng) {
this.cng = cng;
}
public boolean isElectric() {
return electric;
}
public void setElectric(boolean electric) {
this.electric = electric;
}
}
I think it makes sense, but when I asked another question (maybe a stupid example since there can only be either automatic or manual gearbox) https://stackoverflow.com/questions/11747644/selectonemenu-from-declared-fields-list-in-pojo , a user recommend me to use enums instead. Like this way:
public enum Fuel {
DIESEL("diesel"),
GASOLINE("gasoline"),
ETANHOL("etanhol"),
CNG("cng"),
ELECTRIC("electric");
private String label;
private Fuel(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
}
However, since there exists hybrids on the market (like Toyota Prius) the parent class would implement the boolean class at this way:
private Fuel fuel = new Fuel();
and if using enumerated list at this way:
private List<Fuel> fuelList = new ArrayList<Fuel>();
What is the best practice? Keep in mind that I might have 100 different fuels (just for example =). Do not forget that it is an entity and hence persisted in a database.
Thanks in advance =)
It sounds to me like you want an EnumSet, yes, definitely over a bunch of bool's.
This reminds me a lot of the design patterns for flags and I recently posted an SO question on exactly that: Proper design pattern for passing flags to an object
This supports having 100 different fuel types easily. However it doesn't support a car using 100 different fuel types simultaneously easily. But that to me sounds perfectly fine - it would be very hard to build such a car and this is perfectly reflected in the programmatic complexity of coding this :) (Unless of course it really was just supporting all corn-based fuels - in which you might prefer a polymorphic pattern.)
You should definetly use enums.
Image you want to get the fuel-type of an object.
If you would use bools you would end up with something like this:
if (myClass.IsGasoline())
else if (myClass.IsOtherFuel())
else if
...
If you use enums you can simply do something like:
Fuel fuel = myClass.GetFuelType()
(This is just pseudo-code ;))
If the number of hybrids is low, and I guess it will be better to use Enums, and include hybrids as a different case.
Otherwise you will have to manage the logic in a way that can be cumbersome, as when you set a certain Fuel to true you, most likely, will have also to set to false the current one set to true. I am saying this as you have setters for your fuel categories and you don't only define at construction.
EDIT: the way on how to ask for the type of fuel you are using would also be an argument in favor of enums.

Categories