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";
}
}
Related
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);
}
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);
}
I've been reading and googling for hours on how I can call
public class Fee {
int id;
String name;
double amount;
FeeCategory feeCategory; // miscellaneous, other, tuition, etc
GradeLevel gradeLevel;
SchoolYear schoolYear;
String description;
boolean isActive;
public boolean isIsActive() {
return isActive;
}
public void setIsActive(boolean isActive) {
this.isActive = isActive;
}
public FeeCategory getFeeCategory() {
return feeCategory;
}
public void setFeeCategory(FeeCategory feeCategory) {
this.feeCategory = feeCategory;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public GradeLevel getGradeLevel() {
return gradeLevel;
}
public void setGradeLevel(GradeLevel gradeLevel) {
this.gradeLevel = gradeLevel;
}
public SchoolYear getSchoolYear() {
return schoolYear;
}
public void setSchoolYear(SchoolYear schoolYear) {
this.schoolYear = schoolYear;
}
I have a number of different getter methods along with its setter methods.
I need to be able to call the method to fill the cells of a JTable with specific values returned by corresponding getter method.
So what I did was create a DefaultTableCellRenderer
public class JTableRenderer extends DefaultTableCellRenderer{
#Override
public Component getTableCellRendererComponent(
JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int col)
{
Component cellComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
if(row%2 == 0){
cellComponent.setBackground(Color.YELLOW);
}
else{
cellComponent.setBackground(Color.CYAN);
}
for(int i=0; i<table.getRowCount(); i++){
for(int j=0; j<table.getColumnCount(); j++){
if(table.getValueAt(i, j) instanceof Fee){
Fee fee = (Fee)table.getValueAt(i, j);
table.setValue(fee.getId(),i,j);
}
}
}
return cellComponent;
}
}
The problem is with the for loop which I plan to use to set specific values for certain cells.
As you can see, it filled all the cells with just the id because I can't think of a way to iterate through getId(),getName(),getAmount(),getDescription().
Is it possible to put all 4 methods in an array maybe something like
Methods[] myMethods = {getId(),getName(),getAmount(),getDescription()};
then,
for(int i=0; i<table.getRowCount(); i++){
for(int j=0; j<table.getColumnCount(); j++){
if(table.getValueAt(i, j) instanceof Fee){
Fee fee = (Fee)table.getValueAt(i, j);
table.setValue(fee.myMethod[j],i,j);
}
}
}
I want to call just the 4 getter methods but not all of them.
Any solution or suggestion?
You are going to need some sort of switching logic to handle the mapping of index to getter method. For me, the neatest way is to use Java 8 lambda functions, something like the example below. As you can see, this adds a getValue(int index) method to the Fee class which does what you want. The mapping is handled by a Map created in the static initialisation.
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
public class Fee {
private String name;
private int fee;
private static Map<Integer, Function<Fee, Object>> getterIndex = new HashMap<>();
static {
getterIndex.put(0, Fee::getName);
getterIndex.put(1, Fee::getFee);
}
public String getName() {
return name;
}
public Fee setName(String name) {
this.name = name;
return this;
}
public int getFee() {
return fee;
}
public Fee setFee(int fee) {
this.fee = fee;
return this;
}
public Object getValue(int index) {
return getterIndex.get(index).apply(this);
}
public static void main(String[] args) {
Fee fee = new Fee().setName("Barry").setFee(1000);
System.out.println("name: " + fee.getValue(0));
System.out.println("fee : " + fee.getValue(1));
}
}
In order to dynamically call methods like that, you'll need to use reflection and possibly introspection.
Reflection is when you programmatically use the structures of your program itself, such as Class instances, the methods they define. If you take a look at the Java Class class, you'll find it has methods for accessing its constructors, fields, methods and more.
Introspection is the ability to use properties of some object at run-time. Classes that conform to the JavaBeans specification allow introspection, which offers some abstraction that's easier to use than pure reflection. The Introspector class in package java.beans allows you to obtain bean info for a class. From there, the "properties" of that class can be used. A property could be a field with a getter and/or setter, or a getter/setter not backed by a field (that may simply operate on logic). It allows for more than that, such as registering a listener with a property on an instance so that if the property is changed through a setter, the listener is called. This is useful for a model-view-controller approach, where changes to some instance may require update events being fired on the view. For example, if some part of your code changes properties of objects that are represented as rows in your table, outside of the GUI, the listener could be used to update the corresponding cell.
If you want to use an array, you'll have to populate it with Method instances. These would be the read methods (and possibly a separate array with write methods) for the corresponding PropertyDescriptors you get via the introspection. Such a Method can then be invoked on an object, provided the access rules allow it. It might actually be better to use a Map, which maps names to the Method, so the actual order doesn't matter. This would make it easier to refactor your user interface later. You may also want some way of mapping the actual column names to the property names, but if you set specific rules regarding naming and stick to them, you could derive the property names from the column names, or reverse things and show a column for each property automatically.
EDIT: Maybe interesting to know why you need to do these things in such a round-about way. Java does not have first class methods. This means that methods cannot be passed around as arguments or treated as any other piece of data, the way you could in JavaScript or Scala. So reflection is needed to obtain and invoke methods indirectly. Java 8 introduced some functional programming concepts with lambdas, but they are a form of single-method interface in disguise. Furthermore, Java is not a dynamic language such as Ruby or Python, it is a statically compiled language. So some things that are simple (but also easy to break) in other languages require reflection in Java. If you come from a non-Java background, the way you need to do some things may feel cumbersome.
Add to Fee class:
public Object myMethod(int j) {
switch (j) {
case 0:
return this.getId();
case 1:
return this.getName();
case 2:
return this.getAmount();
case 3:
return this.getDescription();
default:
throw new IllegalArgumentException();
}
}
You should have a list of Fee records:
List<Fee> feeData=new ArrayList<Fee>();
Then call:
for(int i=0; i<feeData.size(); i++){
if(feeData.get(i) instanceof Fee){
for(int j=0; j<table.getColumnCount(); j++){
Fee fee = (Fee)feeData.get(i);
table.setValueAt(fee.myMethod(j),i,j);
}
}
}
I'm stuck with a problem here. I want to change the setter from a attribute from the superclass (parent class) in my subclass (child) however when I overide this method in my subclass I can't access my private attributes from the supperclass. And the point is, they have to stay private.
Superclass (problem: setMinimumVoorraad(int voorraad);)
package domein;
public abstract class Artikel implements Weegbaar
{
private String omschrijving;
private double prijs;
private int aantalInStock;
private int minimumVoorraad;
public Artikel(String omschrijving, double prijs, int aantalInStock, int minimumVoorraad)
{
this.setOmschrijving(omschrijving);
this.setPrijs(prijs);
this.setAantalInStock(aantalInStock);
this.setMinimumVoorraad(minimumVoorraad);
}
#Override
public String toString()
{
String output = String.format(" \n omschrijving: %s \n prijs: %f \n In stock %d (minimumvoorraad = %d) \n", this.omschrijving, this.prijs, this.aantalInStock, this.minimumVoorraad);
return output;
}
//----Getters----
public String getOmschrijving() {
return omschrijving;
}
public double getPrijs() {
return prijs;
}
public int getAantalInStock() {
return aantalInStock;
}
public int getMinimumVoorraad() {
return minimumVoorraad;
}
//----Setters----
public void setOmschrijving(String omschrijving) {
this.omschrijving = omschrijving;
}
public void setPrijs(double prijs) {
this.prijs = prijs;
}
public void setAantalInStock(int aantalInStock) {
this.aantalInStock = aantalInStock;
}
public void setMinimumVoorraad(int minimumVoorraad)
{
if(minimumVoorraad < 2)
this.minimumVoorraad = 3;
else
this.minimumVoorraad = minimumVoorraad;
}
}
Subclass
package domein;
public class Food extends Artikel
{
private String houdbaarheidsDatum;
private double nettoGewicht;
public Food(String omschrijving, double prijs, int aantalInStock, int minimumVoorraad, String houdbaarheidsDatum, double nettoGewicht)
{
super(omschrijving, prijs, aantalInStock, minimumVoorraad);
this.setHoudbaarheidsDatum(houdbaarheidsDatum);
this.setNettoGewicht(nettoGewicht);
}
#Override
public boolean isWeegbaar()
{
return true;
}
//----Getters----
public String getHoudbaarheidsDatum() {
return houdbaarheidsDatum;
}
public double getNettoGewicht() {
return nettoGewicht;
}
//----Setters----
public void setHoudbaarheidsDatum(String houdbaarheidsDatum) {
this.houdbaarheidsDatum = houdbaarheidsDatum;
}
public void setNettoGewicht(double nettoGewicht) {
this.nettoGewicht = nettoGewicht;
}
#Override
public void setMinimumVoorraad(int minimumVoorraad)
{
if(minimumVoorraad < 5)
this.minimumVoorraad = 6;
else
this.minimumVoorraad = minimumVoorraad;
}
}
Someone who can help me?
Thanks in advance.
One possibility is to implement the subclass's setter in terms of the superclass's setter (which, presumably, you do have access to).
For example, assuming the setter is setFoo, then the subclass's version might be:
public void setFoo(Foo f) {
// Do subclass stuff pre-setting, if any
super.setFoo(f);
// Do subclass stuff post-setting, if any
}
The answer given above by NPE is absolutely the best way to go about solving this problem. It is elegant and honors basic inheritance contracts between superclass and subclass. Even in your original post, the subclass is actually more restrictive than the superclass, so doing something like:
#Override
public void setMinimumVoorraad(int minimumVoorraad)
{
if(minimumVoorraad <= 5)
super.setMinimumVoorraad(6);
else
super.setMinimumVoorraad(minimumVoorraad);
}
exactly as NPE suggested would probably work. (Note how I modified your if test. Not sure if it's a typo, but in the original implementation 5 would be a valid minimum, but input like 4 would set it to 6.)
Other (possibly acceptable) patterns would be to:
Make the members in your Parent class protected, which would give visibility. (Realize that you did mention a private restriction; this pattern is solely mentioned to provide a more complete overall answer.)
Delegate the validation logic to another method (that is non-private). This way the child can override the validation method.
And now on to the (probably unacceptable) pattern of using Java reflection:
#Override
public void setMinimumVoorraad(int minimumVoorraad) {
try {
Field field = this.getClass().getSuperclass().getDeclaredField("minimumVoorraad");
field.setAccessible(true);
if(minimumVoorraad <= 5)
field.set(this, 6);
else
field.set(this, minimumVoorraad);
field.setAccessible(false);
}
catch(NoSuchFieldException | IllegalAccessException e) {
// do something
}
}
It's worth noting that if you never ever do this in your entire life you will probably be the better for it. Not only does it completely break all contracts, but it relies on hard-coded Strings to do field name lookups, which in and of itself is pretty painful. But it does exist. And no good answer (already given above by NPE) would be complete without an example of how not to do something...
I have a question regarding the best way to implement this. I'm going to describe my current implementation and how I seem to have painted myself into a corner:
I have an abstract class called Package:
public abstract class Package {
protected String description;
protected String packagingCode;
protected Dimension dimensions;
protected Weight weight;
protected Package() {
this.description = null;
this.packagingCode = null;
this.dimensions = null;
this.weight = null;
}
protected Package(String description, String packagingCode, Dimension dimensions, Weight weight) throws ShippingException {
this.description = description;
this.packagingCode = packagingCode;
this.dimensions = dimensions;
this.weight = weight;
String exceptionMessage = "";
if(!meetsWeightRequirements()) {
exceptionMessage = "This package's weight exceeds limits. ";
}
if(!meetsDimensionalRequirements()) {
exceptionMessage += "This package's dimensions exceed limits.";
}
if(!StringUtils.isEmpty(exceptionMessage)) {
throw new ShippingException(exceptionMessage);
}
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getPackagingCode() {
return packagingCode;
}
public void setPackagingCode(String packagingCode) {
this.packagingCode = packagingCode;
}
public Dimension getPackageDimensions() {
return dimensions;
}
public void setPackageDimensions(Dimension dimensions) throws ShippingException {
this.dimensions = dimensions;
if(!meetsDimensionalRequirements()) {
this.dimensions = null;
throw new ShippingException("This package's dimensions exceed limits.");
}
}
public Weight getPackageWeight() {
return weight;
}
public void setPackageWeight(Weight weight) throws ShippingException {
this.weight = weight;
if(!meetsWeightRequirements()) {
this.weight = null;
throw new ShippingException("This package's weight exceeds limits.");
}
}
public abstract boolean meetsWeightRequirements();
public abstract boolean meetsDimensionalRequirements();
}
Then I have classes that extend this abstract class like so:
public class WeightBasedPackage extends Package {
public boolean meetsWeightRequirements() {
Weight weight = this.getPackageWeight();
boolean meetsRequirements = false;
if(weight != null) {
meetsRequirements = (weight.getWeight() > 0);
}
return meetsRequirements;
}
public boolean meetsDimensionalRequirements() {
return true;
}
}
I have another object (ShipRequest) that maintains a List of Packages (List<Package>). I also have a services (eg WeightBasedPackageShipService) that uses this object and can access this list of packages. This implementation has worked fine because the services don't really care what type of package it is. The only difference between the packages is the way they implement the abstract methods.
Now here is where the problem comes in. I created a new class:
public class OrderQuantityPackage extends Package {
int quantity;
public OrderQuantityPackage() {
super();
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public int getQuantity() {
return this.quantity;
}
public boolean meetsWeightRequirements() {
return true;
}
public boolean meetsDimensionalRequirements() {
return true;
}
}
Which has a quantity field. I need to access this field in the service (OrderQuantityPackageShipService). However, since it is of type Package I have to cast it (it seems kinda kludgey).
My question is, how do I implement this in a better fashion (so I don't have to cast) and also ensure type-safety (So that if you are using OrderQuantityPackageShipService, the package must be of type OrderQuantityPackage). I thought about using Generics, but it seems a little to kludgey for what I am trying to do (ShipRequest has a bunch of other attributes and it seemed strange to genericize it based on the type of package).
Thanks.
public abstract class Package {
protected String description; // These shouldn't be private fields instead of protected?
protected String packagingCode; // Nah, I don't think so, otherwise how could I store a value into the Quantity field? =P
protected Dimension dimensions;
protected Weight weight;
protected int quantity;
// Constructors, getters and setters...
public virtual int getQuantity {
throw new NotImplementedException();
}
public virtual int setQuantity(int quantity) {
throw new NotImplementedException();
}
}
public final class OrderQuantityPackage extends Package {
public override int getQuantity {
return super.quantity;
}
public override void setQuantity(int quantity) {
super.quantity = quantity;
}
}
I'm not completely sure about the syntax though, and neither about the NotImplementedException, but I hope you get the idea. So, any Package derived class that needs or require a quantity may do so by overriding the getter and setter of the Quantity property.
No exception should be thrown as of where the Quantity won't be required, it shouldn't get called, so no exception shall be thrown. Furthermore, it testifies that your model only does what it is required when times come.
In addition to it, OrderQuantityShipService shouldn't require a Weight property within the OrderQuantityPackage, and as written by Vivin, one could access the weight anyway.
Otherwise, a simple cast within your service should do it. It is no dirty way to go to use casting. For instance, one must cast the sender object within an event handler to the proper control type he wishes to check for name, state or other property values! The most general class is then passed on to the event, and one must cast... And this, that is not me who said to opt this way, these are software engineers!...
EDIT Vivin, how do one cast from a data type to another in JAVA, is it as in C/C++/C# ?
CastedType variable = (CastedType)TypeCast;
Short Answer: Dependency Inversion
You have a OrderQuantityPackageShipService class that requires certain features from the objects that it processes. So OrderQuantityPackageShipService should be the one specifying those requirements. Typically this is done with an interface. If it is very specific to the service, create the interface nested. ie:
class OrderQuantityPackageShipService {
//...
interface QuantityPackage {
int getQuantity();
// ...
}
}
if it can be used in a consistent manner by other services, define it outside of the OrderQuantityPackageShipService class.
Then have certain packages implement that interface...
Maybe you should create an abstract service and extend it for the different kinds of packages to handle. You could have the handling method be abstract and have each kind of service know what to do with the corresponding package. If you're not to mix types of packages then this might work.
One thing I can think of is why would you need to access the quantity attribute in the class OrderQuantityPackageShipService ? As I look at it you have a getter and setter for each attribute of the class Package. Are these getters and setters really needed ? Having getters/setters for all those attributes doesn't go well with encapsulation.
Can you think of providing public methods in Package class that operate at a higher level and don't expose the internal attributes ? Wouldn't that help ?