Unable to map target properties using constructors with mapstruct - java

I am using MapStruct 1.5.2.Final
Map struct is unable to map the target values using the parameterised constructor. Following is the parameterised constructor for the class.
I know that if I would have exposed the setters, this would have worked.
I don't want to expose the setters for my class as I want my class to be immutable.
#JsonCreator
public PassengerInfo(
#JsonProperty("a") final String a,
#JsonProperty("b") final String b) {
this.a = a;
this.b = b;
}
I am getting the following error
error: Property "a" has no write accessor in class.
error: Property "b" has no write accessor in class.
Also, this is the only constructor in my class.
Following is my class
public class Clazz {
private final String a;
private final String b;
#JsonCreator
public Clazz(
#JsonProperty("a") final String a,
#JsonProperty("b") final String b) {
this.a = a;
this.b = b;
}
public String getA() {
return a;
}
public String getB() {
return b;
}
}

Your code seems fine. There must be something else in your project.
#Getter
#Setter
public class PassengerEntity {
private String a;
private String b;
}
public class PassengerInfo {
private final String a;
private final String b;
#JsonCreator
public PassengerInfo(
#JsonProperty("a") final String a,
#JsonProperty("b") final String b) {
this.a = a;
this.b = b;
}
public String getA() {
return a;
}
public String getB() {
return b;
}
}
#Mapper
public interface PassengerMapper {
PassengerInfo mapPassenger(PassengerEntity entity);
}
class PassengerMapperTest {
private PassengerMapper passengerMapper;
#BeforeEach
void setUp() {
passengerMapper = Mappers.getMapper(PassengerMapper.class);
}
#Test
void testMapper() {
PassengerEntity entity = new PassengerEntity();
entity.setA("valueA");
entity.setB("valueB");
PassengerInfo info = passengerMapper.mapPassenger(entity);
Assertions.assertEquals("valueA", info.getA());
Assertions.assertEquals("valueB", info.getB());
}
}
=> test is OK

Related

add custom code to auto generated setters

Is there a way to tell Lombok to append a piece of code to each generated setter?
Example:
#Setter
public class Foo {
private int a;
private int b;
private void update() { /* ... */ }
}
would generate
public void setA(int a) {
this.a = a;
update();
}
public void setB(int b) {
this.b = b;
update();
}

Allow instantiate of specific variables of a class based on the variable value

I have a use case where I have to instantiate a given class with only specific variables based on the value of variable (let say in this example) typeName. For a variable String typeName, if its value is TYPE-1, only specific set of variables (a,b,c) should be allowed to be instantiate. Similarly if its value is TYPE-2, only the another set of variables (x,y,z) should be allowed to instantiate.
if(typeName == "TYPE1")
{
CentralClass class = new CentralClass(a,b,c); //initiating only variable a,b,c
}
else
{
CentralClass class = new CentralClass(x,y,z); //initiating only variable x,y,z
}
Class Structure
public class CentralClass {
String typeName; //ALLOWED Values TYPE1, TYPE2
String x;
String y;
String z;
String a;
String b;
String c;
}
What would be the best way to do so via any design pattern etc.
Note: The structure of the class is open for change. We can have multiple classes(clubbing different variables), inner, static classes, or any design pattern enforced etc.
Answer
The builder pattern is perfect for your usecase. It will allow you to create an object with only certain fields. It is better to use a builder than to pass in "null" into a constructor for the fields you do not have.
You can quickly add all the builder methods using Lombok.
Side-notes
Only having half of the values filled in with a class is usually a sign you should create separate classes.
When you say "typeName" can only have values "TYPE1" or "TYPE2", you should be using an enum instead of String. This anti-pattern is often called primitive obsession.
Solution Code
Builder pattern (without Lombok)
public class CentralClass {
String typeName; //ALLOWED Values TYPE1, TYPE2
String x;
String y;
String z;
String a;
String b;
String c;
CentralClass(String typeName, String x, String y, String z, String a, String b, String c) {
this.typeName = typeName;
this.x = x;
this.y = y;
this.z = z;
this.a = a;
this.b = b;
this.c = c;
}
public static CentralClassBuilder builder() {
return new CentralClassBuilder();
}
public static class CentralClassBuilder {
private String typeName;
private String x;
private String y;
private String z;
private String a;
private String b;
private String c;
CentralClassBuilder() {
}
public CentralClassBuilder typeName(String typeName) {
this.typeName = typeName;
return this;
}
public CentralClassBuilder x(String x) {
this.x = x;
return this;
}
public CentralClassBuilder y(String y) {
this.y = y;
return this;
}
public CentralClassBuilder z(String z) {
this.z = z;
return this;
}
public CentralClassBuilder a(String a) {
this.a = a;
return this;
}
public CentralClassBuilder b(String b) {
this.b = b;
return this;
}
public CentralClassBuilder c(String c) {
this.c = c;
return this;
}
public CentralClass build() {
return new CentralClass(typeName, x, y, z, a, b, c);
}
}
}
Builder pattern (with Lombok)
#Builder
public class CentralClass {
String typeName; //ALLOWED Values TYPE1, TYPE2
String x;
String y;
String z;
String a;
String b;
String c;
}
Usage
if(variable == "TYPE1")
{
CentralClass aClass = CentralClass.builder()
.a("A")
.b("B")
.c("C")
.build();
}
else
{
CentralClass aClass = CentralClass.builder()
.x("X")
.y("Y")
.z("Z")
.build();
}
Read more:
https://dzone.com/articles/design-patterns-the-builder-pattern

Access instance property from enclosed class

I'm a newbie on java, in this example is it possible to get the id of ClassA from ClassB?
public class ClassA {
private Long id;
private List<ClassB> listOfClassB;
[...]
}
public class ClassB {
private Long num;
public boolean isValidRow() {
return this.num > ***ClassA.this.getId()***;
}
[...]
}
For getting the id field of ClassA, you need to have an instance of ClassA in ClassB, for example:
public class ClassA {
private Long id;
private List<ClassB> listOfClassB;
[...]
}
public class ClassB {
private Long num;
private ClassA a;
public ClassB(Long num, ClassA a) {
this.num = num;
this.a = a;
}
public boolean isValidRow() {
return this.num > a.getId();
}
[...]
}
And initiate it this way:
new ClassB(1, new ClassA(...));
Try the following:
public class ClassB {
private ClassA a;
private Long num;
public ClassB(ClassA a){
this.a=a;
}
public boolean isValidRow() {
return this.num > a.getId();
}
}
Use it as follows:
...
ClassA a = new ClassA();
ClassB b = new ClassB(a);
...
Or if you create Bs inside A:
ClassB b = new ClassB(this);
This will work for nested classes only:
class ClassA {
private long id;
class ClassB {
ClassA.this.getId(); // Will work here
}
}
To make it work in your case you need inject instance of ClassA to instance of ClassB:
class ClassA {
long id;
}
class ClassB {
private ClassA a;
ClassB(ClassA a) {
this.a = a;
}
void someMethod() {
long id = a.getId();
}
}
You cannot get the id of ClassA, but you can get it from instance of ClassA
For example:
ClassA a =new ClassA():
ClassB b =new ClassB(a);
ClassA:
public class ClassA{
private Integer id;
public Integer getId(){return id;}
}
ClassB:
public class B {
//whatever
private A a;
public B(A a){
this.a=a;
}
public void someMethod(){
//whatever
t.getId() // here you have the id.
}
}
now everywhere in your ClassB you will have access to a.getId().

Intellij - refactor getters and setters using delegate class

Here's what I'd like to do. Let's say I have this code:
public class Foo {
private Bar bar = new Bar();
public void doWork() {
bar.setA(5);
bar.setB(10);
}
}
public class Bar {
private int a;
private int b;
public void setA(int a) { this.a = a; }
public void setB(int b) { this.b = b; }
...
}
I want to extract members a and b from Bar into a separate Container class and end up with this code. Notice that Foo doesn't call setA on bar anymore, instead it requests container and calls a setter on it instead:
public class Foo {
private Bar bar = new Bar();
public void doWork() {
bar.getContainer.setA(5);
bar.getContainer.setB(10);
}
}
public class Bar {
private Container container;
public Container getContainer() { return container; }
...
}
public class Container {
private int a;
private int b;
public void setA(int a) { this.a = a; }
public void setB(int b) { this.b = b; }
...
}
Is there a way to do this in IntelliJ?
I could try using Refactor -> Extract -> Delegate, but in that case IntelliJ leaves setA and setB methods in Bar and doesn't change code in Foo:
public class Bar {
private Container container;
public void setA(int a) { container.setA(a); }
public void setB(int b) { container.setB(b); }
...
}
which is not quite what I want.
Select the piece of code inside class bar...
private int a;
private int b;
public void setA(int a) { this.a = a; }
public void setB(int b) { this.b = b; }
On the main menu, or from the context menu of the selection, choose Refactor | Extract | Method Object . You will also have option to choose to create inner class, or anonymous class. Hope this helps.

Changing a java object outside its class

Here's my question, how can I change an object outside of it's class, so that it maintains the changes made in the outside class?
Here's an example of the code:
Main class:
public class Main {
public static void main(String[] args)
{
Variable var = new Variable(1,2,3);
Change.changeVar(var);
System.out.println("" + var.geta() + "" + var.getb() + "" + var.getc());
}
}
Variable class:
public class Variable {
private int a;
private int b;
private int c;
public Variable(int a, int b, int c)
{
this.a = a;
this.b = b;
this.c = c;
}
public int geta()
{
return this.a;
}
public int getb()
{
return this.b;
}
public int getc()
{
return this.c;
}
}
Change class:
public class Change {
public static void changeVar(Variable var)
{
Variable var2 = new Variable(4,5,6);
var = var2;
}
}
In your example, no. When changeVar() exits, the parameter var is discarded, and the var in your main() method retains its original value. Read up on pass by reference.
public class Variable {
private int a;
private int b;
private int c;
public Variable(int a, int b, int c)
{
this.a = a;
this.b = b;
this.c = c;
}
public int geta()
{
return this.a;
}
public int getb()
{
return this.b;
}
public int getc()
{
return this.c;
}
// depending on your use case, setters might be more appropriate
// it depends on how you want to control the changing of the vars
public void update(int a, int b, int c) {
this.a = a;
this.b = b;
this.c = c;
}
}
public class Change {
public static void changeVar(Variable var)
{
var.update(4,5,6);
}
}
You cannot do it in a way that you described, because in Java variables are passed by values. However you can achieve the desired effect in a different way:
public class Variable {
private int a;
private int b;
private int c;
public Variable(int a, int b, int c)
{
this.a = a;
this.b = b;
this.c = c;
}
public int geta()
{
return this.a;
}
public int getb()
{
return this.b;
}
public int getc()
{
return this.c;
}
public void seta(int a) { this.a = a; }
public void setb(int b) { this.a = b; }
public void setc(int c) { this.a = c; }
}
public class Change {
public static void changeVar(Variable var)
{
var.seta(4);
var.setb(5);
var.setc(6);
}
}
You need to provide setter methods and call them on the original object:
public void seta(int newa) { this.a = newa; }
Then you would say
public static void changeVar(Variable var)
{
var.seta(4);
//etc
}
You are merely repointing the local variable reference var to point to your new instance var2. It has no effect on the value of the original instance passed into the method.
Doing it that way? You can't.
You're passing a reference to the instance. However, inside the function, you use a new reference. Assigning to the new reference does not affect others.
public static void changeVar(Variable var)
{
Variable var2 = new Variable(4,5,6);
var = var2;
}
first, u can write some setter methods in Variable class, then you can call these setter methods in the above code, like var.setA(4) ... and so on.enter code here

Categories