Rest application using hateoas: Multiple markers at this line - java

I am trying to make a rest application using hateoas.
Here is my assembelr class:
public class PlantInventoryEntryAssembler extends ResourceAssemblerSupport<PlantInventoryEntry, PlantInventoryEntryDTO>
{
}
PlantInventoryEntryDTO class is:
#Data
public class PlantInventoryEntryDTO extends ResourceSupport{
Long id;
String name;
String description;
#Column(precision = 8, scale = 2)
BigDecimal price;
public Long idGetter (){
return id;
}
}
the problem is, in line #Data (i use lombok) i have faced with the following error:
Multiple markers at this line
- overrides org.springframework.hateoas.ResourceSupport.equals
- The return type is incompatible with ResourceSupport.getId()
- Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If
this is intentional, add '#EqualsAndHashCode(callSuper=false)' to your type.
- overrides org.springframework.hateoas.ResourceSupport.toString
- overrides org.springframework.hateoas.ResourceSupport.hashCode
- overrides org.springframework.hateoas.ResourceSupport.getId
How can i handle it?
Update:
PlantInventoryEntry class
#Entity
#Data
public class PlantInventoryEntry {
#EmbeddedId
PlantInventoryEntryID id;
String name;
String description;
#Column(precision = 8, scale = 2)
BigDecimal price;
}

Rename the field id in PlantInventoryEntryDTO (to, say, entryId).
The only error in those "multiple markers" is The return type is incompatible with ResourceSupport.getId(), the others are warnings.
ResourceSupport defines a getId() method with a return type of Link. Lombok tries to add another getId() method with the return type long for the id field in PlantInventoryEntryDTO. Since their return types are incompatible, the compiler won't override the original method.

Related

Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object

I am getting below error while using lombok and even it doesn't allow me to set id and version while creating student instance.
Multiple markers at this line
- overrides com.example.demo.IModel.canEqual
- Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is
intentional, add '#EqualsAndHashCode(callSuper=false)' to your type.
- overrides com.example.demo.IModel.hashCode
- overrides com.example.demo.IModel.toString
- overrides com.example.demo.IModel.equals
IModel
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class IModel {
private String id;
private String version;
}
Student
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class Student extends IModel{
private String firstName;
private String lastName;
}
In the main method, it doesn't allow me to set the value of Id and version field
Student s = Student.builder().firstName("Adam").lastName("Kerr").build();
Edit-1
#sfiss - As suggested, now I changed like below, but now I am not able to set firstName and lastName, only cab set id and version
Student.java
#Data
#Builder(builderMethodName = "studentBuilder")
#NoArgsConstructor
#AllArgsConstructor
#EqualsAndHashCode(callSuper = true)
public class Student extends IModel {
#NotEmpty(message = "{email.notempty}")
#Email
private String firstName;
private String lastName;
public Student(final String firstName, final String lastName, final String id, final String version) {
super(id, version);
this.firstName = firstName;
this.lastName = lastName;
}
}
IModel.java
#Builder
#Data
#NoArgsConstructor
#AllArgsConstructor
public class IModel {
private String id;
private String version;
}
There are multiple problems here, all of them relating to using lombok with inheritance:
Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is
intentional, add '#EqualsAndHashCode(callSuper=false)' to your type.
The warning is given by #Data because that usually generates equals/hashcode without the call to super. Fix it by adding #EqualsAndHashCode(callSuper = true).
The #Builder gives you a compile warning because it will generate two static methods with the same name in both the super- and the subclass. Fix it by defining #Builder(builderMethodName = "studentBuilder") on Student.
You won't be able to set superclass properties on you studentBuilder because your superclass and subclass have a default constructor. Fix it by creating a constructor and moving the #Builder annotation to it (i.e. annotate the constructor with #Builder, not the class):
Code:
#Builder(builderMethodName = "studentBuilder")
public Student(
final String firstName,
final String lastName,
final String id,
final String version) {
super(id, version);
this.firstName = firstName;
this.lastName = lastName;
}
Call your builder with the correct method (IModel.builder() vs Student.studentBuilder()):
Student.studentBuilder().firstName("Name").build();
I also want to add some improvements to the above solution. While I like lombok as a tool (I really don't need to read that much boilerplate), the first solution to preventing boilerplate is to think whether you need all those getters and setters and ask yourself these questions:
Do you want bags of data? It is fine for some use cases, in others you want objects more in the sense of OOP, i.e. don't expose your state but behavior.
Do you really need mutability? If not, prefer #Value.
Do you really need both constructor types (especially the no-args-constructor)? They are part of the problem here. Sometimes you need them for frameworks (proxies, reflection, ...) to work properly.
More specific to your code: You prefixed the superclass with "I" but it is not an interface. If it is meant as an abstract class, declare it abstract and don't give it a #Builder.
You can use #sfiss solution
or
You can use #Getter and #Setter annotations instead of #Data annotation.
The warning from building a Spring Boot project
When I built my Spring boot project, I got 20 warnings about a same thing. The warning shows: Generating equals/hashCode implementation but without a call to superclass
Description of the warning
This warning is from lombook, it happens when we inherit a child class from parent class by using #Data #ToString #EqualsAndHashCode, IDE will trigger the warning: Generating equals/hashCode implementation but without a call to superclass .
Solution
There are two solutions:
add annotation #EqualsAndHashCode(callSuper = true) on the class
create lombook config file in the project root path: src/main/java. Note: this solution requires the version of lombook > 1.14.
I recommend the solution 2, since you will not need to add the annotation to all the required classes.
To impletement the solution, you need to create lombok.config in the path of src/main/java. If you have more than one packages, you may need to create multiple config files.
The content of the config file includes:
config.stopBubbling=true
lombok.equalsAndHashCode.callSuper=call
When we rebuild our project, you will not get these warnings anymore.
Cheers!
I had the same problem and i resolved it in this way hope it helps you.
That help you also with abstract classes
Student.java
#Data
#NoArgsConstructor
#AllArgsConstructor
#EqualsAndHashCode(callSuper = true)
public class Student extends IModel {
#NotEmpty(message = "{email.notempty}")
#Email
private String firstName;
private String lastName;
#Builder
public Student(final String firstName, final String lastName, final String id, final String version) {
super(id, version);
this.firstName = firstName;
this.lastName = lastName;
}
}
IModel.java
#Data
#NoArgsConstructor
#AllArgsConstructor
public class IModel {
private String id;
private String version;
}
The error says If this is
intentional, add '#EqualsAndHashCode(callSuper=false)' to your type.
So, add #EqualsAndHashCode(callSuper = false) to solve the problem.

Getting around Json jackson and lombok constructor requirements

Using json to save and load data requires a constructor for json to load the object, and I'm having trouble getting lombok annotations to work with this. What should I do?
This is what my class looked like before and after attempting to use an annotation to construct my item:
#Data
public class Item { //before
private int id;
private int amount;
public Item(#JsonProperty("id") int id, #JsonProperty("amount") int amount) {
this.id = id;
this.amount = amount;
}
}
#Data
#AllArgsConstructor
#NoArgsConstructor //I don't want this here as it could cause complications in other places. But json requires I have this...
public class Item { //after
private int id;
private int amount;
}
I don't want to use the NoArgsConstructor annotation by lombok as I don't want a no args constructor for this class. I realise that I could do this:
private Item() {
}
But was hoping there is a better way...
Since lombok 1.18.4, you can configure what annotations are copied to the constructor parameters. Insert this into your lombok.config:
lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonProperty
Then just add #JsonProperty to your fields:
#Data
#AllArgsConstructor
public class Item {
#JsonProperty("id")
private int id;
#JsonProperty("amount")
private int amount;
}
Although the annotation parameters may seem unnecessary, they are in fact required, because at runtime the names of the constructor parameters are not available.
try adding this to your lombok config file:
lombok.anyConstructor.addConstructorProperties=true
config.stopBubbling = true
So what you're saying is that Jackson requires no-args constructor for deserialization, and you don't want to add no-args constructors to your classes because that doesn't play well with your model.
Lombok is completely irrelevant here - it makes zero difference whether no-args constructor would be written manually or generated by Lombok, it'll still be just a no-args constructor.
Your real question is - can I make Jackson work without no-argument constructors on target classes. There are multiple answers to that already, you have almost done it. Here's what has to be done:
Add #JsonCreator annotation to your constructor
Add #JsonProperty("propName") to constructor parameters
You did the #2 but not #1. Add that and this should fix your problem.

Overriding #JsonProperty in a subclass with #JsonIgnore

I have a parent class
public class Parent {
#JsonProperty("ID")
private int id;
// getter and setter
}
and a corresponding subclass
public class Child extends Parent {
#Override
#JsonIgnore
public int getId() {
return id;
}
}
While the field id should be serialized for Parent and other subclasses, I do not want to include it in the specific subclass Child. However, the annotation #JsonIgnore doesn't override the annotation #JsonProperty and the id is also included when serializing the Child.
Interestingly, it works with #JsonIgnoreProperties("ID") at class level of Child, but I would like to know how it can be accomplished at method level and why my approach doesn't work.
I am using Jackson in version 2.9.6.

How to import value from properties file and use it in annotation?

I have a class that is an entity:
Class.java
#Entity
public class Class {
#Id
#GeneratedValue
private Long id;
#NotNull
#Range(min = 0, max = 10)
private double value;
}
I want to get rid of the hard-coded values from the #Range annotation and load them from a configuration file.
constraints.properties
minVal=0
maxVal=10
This is what I've tried:
#Component
#Entity
#PropertySource("classpath:/constraints.properties")
public class Class {
#Value("${minVal}")
private final long minValue;
#Value("${maxVal}")
private final long maxValue;
#Id
#GeneratedValue
private Long id;
#NotNull
#Range(min = minValue, max = maxValue)
private double value;
}
The error I get is attribute value must be constant. How the initialization of these fields should be performed to get the result I want?
First: to inject values into a final field you have to use constructor injection see this question
This means that you pass some unknown value into the constructor.
Although the value never changes it is not constant, since the compiler cannot know this value, because its determined at runtime. And you can only use expressions as values of annotation whose value can be determined at compile time.
Thats because annotations are declared for a class not for a single instance and in your example the values of the variables are potentially diffrent for every instance.
So I would say, that what you want to achieve is not possible.

JaxB cannot be cast to java.lang.Integer

I have an abstract class:
#MappedSuperclass
public abstract class BaseEntity<K>
{
#Temporal(value = TemporalType.TIMESTAMP)
private Date cadastrado;
#Temporal(value = TemporalType.TIMESTAMP)
private Date modificado;
#Column(length = 30)
private String ip;
private String autorModificacao;
public abstract K getId();
public abstract void setId(K id);
...
and a derived class:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Pessoa extends BaseEntity<Integer> implements Serializable {
#Id
#ColumnGridPF
#GeneratedValue(strategy = GenerationType.AUTO, generator = "pessoa")
private Integer id;
....
#Override
Integer getId() {
return id;
}
#Override
public void setId(Integer id) {
this.id = id;
}
....
when my application try to unmarshall the object, I get an error
**
SEVERE: The RuntimeException could not be mapped to a response, re-throwing to the HTTP container
java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.ElementNSImpl cannot be cast to java.lang.Integer
at br.com.sigmaonline.entity.cadastro.pessoa.Pessoa.setId(Pessoa.java:46)
at br.com.sigmaonline.entity.common.generic.BaseEntity$JaxbAccessorM_getId_setId_java_lang_Object.set(MethodAccessor_Ref.java:60)
**
Can Any one help me?
By default when your JAXB (JSR-222) implementation is creating metadata for Pessoa it is also going to create metadata for the super class BaseEntity. Since JAXB by default considers properties as mapped it is going to consider that it has a property called id of type Object. When JAXB doesn't know the type of the property it will convert it to a DOM Element. This is resulting in the ClassCastException.
Solution
The solution really depends upon whether or not you want BaseEntity considered part of the inheritance hierachy (see: http://blog.bdoughan.com/2011/06/ignoring-inheritance-with-xmltransient.html). But what I would recommend is either leveraging #XmlTransient or #XmlAccessorType(XmlAccessType.NONE) on BaseType to remove problematic properties:
http://blog.bdoughan.com/2012/04/jaxb-and-unmapped-properties.html

Categories