In FindBugs, I am getting an issue like FCBL_FIELD_COULD_BE_LOCAL on the class name line of this code:
#Entity
#Table(name = "Student")
#Immutable
#Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class RetrievableStudent extends BaseStudent
{
#Id
#Column(name = "STUDENT_ID")
private long studentId;
#Column(name = "STUD_NOTE")
private String studenetNote;
}
How can I resolve this issue?
In order to resolve that issue you need to use you fields somewhere in your class. What FindBugs is telling you is that your fields in your class are never used as the fields.
How you using your fields that were retrieved from database? Maybe you need to add getters? For now, your fields are useless (unless you don't using them with reflection, which is not good).
My POJO has already getters setters, equals, hashcode.
It worked when I tried adding #JsonProperty annotation, as my POJO is built for API response purposes.
If the POJO is for ORM purposes (means database entity) the on getters and setters #Column annotation should work.
Related
I occasionally get the following error:
org.hibernate.LazyInitializationException: could not initialize proxy [com.dd.translation.domain.postgres.Offer#OfferKey(offerId=03Y, difId=b3e79b1925ce4e41905a2ce214943d1f)] - no Session
Embeddable:
#Builder
#Embeddable
#Data
#NoArgsConstructor
#AllArgsConstructor
public class OfferKey implements Serializable {
#Column(name = "offer_id", columnDefinition = "CHARACTER VARYING(64) NOT NULL")
private String offerId;
#Column(name = "dif_id", columnDefinition = "CHARACTER VARYING(64) NOT NULL")
private String difId;
}
Embedded object:
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Table(name = "offers")
public class Offer {
#EmbeddedId
private OfferKey offerId;
private LocalDateTime validDate;
}
There is no other lazy loading in this project and I wouldn't assume I would need #Transactional for it. I am trying to figure out if there is a way to manually set it to eager or if anyone has run into this issue. I personally do not use this pattern but it is in existing code and I am trying to figure out if I need to rip it out or if there is an easy fix.
The error is telling you that the Offer object you are trying to access is not initialized, not the embedded id.
I guess you have something like this in one of your models:
#ManyToOne(fetch = FetchType.LAZY)
Offer offer;
Wherever you load the entity containing that association, you will have to make sure the offer is properly initialized, as apparently the calling code expects it can access offer details.
You can change the FetchType to EAGER, but I wouldn't recommend that. The better solution would be to apply a #EntityGraph on the repository method that instructs it to load the association.
I have confusion in using Data annotation to DTO class. Here is my sample class.
#Data
public class MyClass {
private Long id;
private String name;
}
I've read online that using Data annotation specifically on DTO class will allow the values of the fields to be changed by use of the generated setters.
Should I remove the lombok Data annotation? And implement the getters and setters manually.
Thanks :)
I would avoid #Data for DTOs since it has too many pitfalls. First of all as you mentioned it is mutable which you don't really want for a DTO. And despite it being mutable, it implements equals() and hashCode() which is only asking for trouble.
You can use #Value for an immutable DTO. For an incoming DTO you may need to add lombok.anyConstructor.addConstructorProperties to your lombok.config, which will allow libraries like jackson to deserialize to your POJO without a default constructor.
The annotation #Data comes from the Project Lombok which is designed to use reflection via annotations mostly. This annotation assures generation of all the setters, getters, a constructor with all the required arguments and overridden Object::toString, Object::equals and Object::hashCode methods.
Briefly said, this annotation "completes" a simple POJO object and generates all the boilerplate without a need to use IDE.
They named the annotation #Data because they support the idea of the understanding objects as data containers only.
As far as I understand, the generation happens only for the missing getters/setters (let's speak about them for brevity). The generated getters/setters are in their pure form as you know:
public int getId() { return this.id; }
public void setId(int id) { this.id = id; }
You can use more verbose setter/getter performing validation or anything similar which override the generated ones. You can both use #Data annotation and write your ones manually.
DTO is used to transmit data information, some information is actually we do not want users to be able to change or access, such as the user password, we do not want to pass to the front end when the user can see the encrypted password, or we do not want users to modify the password while changing their information, and what works in this serialization process is setter and getter, and data annotations that automatically generate getters and setters for all fields.
For example
#Data
class User{
private String userName;
private String pwd;
}
This class, will have all setter and getter. When you trans to web, you will see
{userName: "123", pwd: "xxx"}
This is terrible.
But if you use DTO
class User{
private String userName;
private String pwd;
public String getUserName(){
return userName;
}
}
They only see
{userName: "123"}
By default the #Data lombok annotation will generate setters and getters for all fields in the class.
If you want an immutable data transfer object, annotate it as #Value instead.
If you want a mixure of some immmutable values and some mutable values in your MyClass type, for instance you might want the id field to be immutable and the rest mutable, you would use the #Setter annotation on the field you want to be immutable, specifying an AccessLevel of NONE. For instance:
#Data
public class MyClass {
#Setter(AccessLevel.NONE)
private Long id;
private String name;
}
This will generate a getter but no setter for the id, and a getter and setter for the name.
I'm trying to create JPA entities by using inheritance , I am not using any JPA polymorphic mechanism to do this. The reason is I want model classes to be independent, so if I want to use JPA I can extend the same model classes and create JPA entities and get the job done. My question is, is this possible to achieve without using JPA polymorphic mechanism, because when I try to deal with the JPA entities created after extending the model classes I don't see the properties that are inherited from super class but I can see new properties in the table if I add new properties in to the extended JPA entity.
Here are my entities:
#Data
public abstract class AtricleEntity {
protected Integer Id;
protected String title;
protected Integer status;
protected String slug;
protected Long views;
protected BigDecimal rating;
protected Date createdAt;
protected Date updatedAt;
}
#Data
#Entity
#Table(name="articles_article")
#RequiredArgsConstructor
public class Article extends AtricleEntity {
public static final String TABLE_NAME = "articles_article";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer Id;
private String title;
}
#Repository
public interface ArticleRepository extends JpaRepository<Article, Integer>{}
I can see a table with a column title created if i run this. that's because I've explicitly added that property in Article , but i want other columns to appear in the table with the help of java inheritance. is this possible?
Simple answer is NO. JPA cannot use object's inheritance out of the box coz of the simple reason that other children will have different column names and other parameters and might choose not even to save these columns.
So JPA has it's own inheritance mappings which an object might have to follow. Usage like MappedSuperclass might help.
Reference : http://www.baeldung.com/hibernate-inheritance for hibernate.
#MappedSuperclass annotation put on your super class should help.
https://docs.oracle.com/javaee/5/api/javax/persistence/MappedSuperclass.html
I have a JPA #Entity class Place, with some properties holding some information about a place, such as name of place, description, and URLs of some images.
For the URLs of images, I declare a List<Link> in my entity.
However, I am getting this error:
Basic attribute type should not be a container.
I tried to remove #Basic, but the error message is still there. Why does it shows this error?
You can also use #ElementCollection:
#ElementCollection
private List<String> tags;
You are most likely missing an association mapping (like #OneToMany) and/or #Entity annotation(s).
I had a same problem in:
#Entity
public class SomeFee {
#Id
private Long id;
private List<AdditionalFee> additionalFees;
//other fields, getters, setters..
}
class AdditionalFee {
#Id
private int id;
//other fields, getters, setters..
}
and additionalFees was the field causing the problem.
What I was missing and what helped me are the following:
#Entity annotation on the generic type argument (AdditionalFee) class;
#OneToMany (or any other type of association that fits particular business case) annotation on the private List<AdditionalFee> additionalFees; field.
So, the working version looked like this:
#Entity
public class SomeFee {
#Id
private Long id;
#OneToMany
private List<AdditionalFee> additionalFees;
//other fields, getters, setters..
}
#Entity
class AdditionalFee {
#Id
private int id;
//other fields, getters, setters..
}
Change #basic to #OneToMany for List types
Or you can mark it as #Transient if it doesn't exist on DB table.
#Transient
private List<String> authorities = new ArrayList<>();
As the message says, #Basic should not be used for containers (e.g. Java collections). It is only to be used for a limited list of basic types. Remove the #Basic annotation on that field.
If, as you say in the question, the error message is still there, you might need to try the following steps in order:
Save the file
Close and reopen the file
Clean and rebuild the project
Restart the IDE
(these are generic steps, which I use when an IDE is generating a compilation error that obviously makes no sense.)
This can also happen when your class is missing its #Entity annotation. When you get weird warnings like these, sometimes it helps to try and compile and see if the compiler complains.
The error seems not have impact on GAE since I can run the app and store data into storage. I guess it's a bug in IntelliJ IDEA and you can simply ignore it.
'Basic' attribute type should not be a container
This error occurs when you declare an existing entity as an attribute in the current Entity without declaring the relationship type which could be either of the JPA relationships.
Detailed Article on JPA relationships
I've implemented a REST API based on JPA and JAXB.
I have a classes roughly like this (very simplified):
#Entity
#XmlRootElement
...
public class Thing {
#Id
#GeneratedValue
...
#XmlAttribute
#XmlID
#XmlJavaTypeAdapter(JAXBLongAdapter.class)
private Long id;
...
}
Hibernate (my current JPA provider) generates numbers as the id value, but they are naturally unique only for one one type, Thing in this example.
Now XSD says that xsd:id (#XmlID) is a NCString which cannot be a plain number so i prepended a '_' to numbers in the JAXBLongAdapter. - like '_1'
Now the schema validator complains:
[org.xml.sax.SAXParseException: cvc-id.2: There are multiple occurrences of ID value '_1'.]
If I understand this correctly a xsd:ID element must have a (string) value that is globally unique in the xml document. But this is very opposite of the common way of using IDs in databases.
What do I do now?
I thought of three things:
Create a JAXBLongAdapter for each type with a type specific prefix?
Using another JPA id generator, perhaps UUID? - But which one?
Stop using #XmlID and #XmlIDREF, which creates redundancy and general messiness.
It seems that I now have to change the Database schema to use different IDs.
- But it would be nice if the IDs stayed short, because they appear in URLs.
My question: Is there a ID generator that is comparably fast and is globally unique?
Or is there another way of tackling this?
EDIT:
This hack kinda works, leaving the JPA IDs intact.
#XmlID
#XmlAttribute(name="id")
private String getXmlID(){
return String.format("%s-%s", this.getClass().getSimpleName(), this.getId().toString());
}
private void setXmlID(String xmlid){
String prefix = String.format("%s-", this.getClass().getSimpleName());
if(xmlid.startsWith(prefix)){
this.id = Long.parseLong(xmlid.substring(prefix.length()));
}else{
throw new IllegalArgumentException(xmlid+" does not look like "+prefix+"###");
}
}
By moving the JAXB Annotation from the field to dedicated private getters/setters for the XmlID.
That's exactly what I had done with for some time.
You can ask yourself what is actually #XmlID for this domain object when marshalled?
I once thought #XmlID and #XmlIDREF can solve the circular problem in JAXB.
Here comes what I'm doing with my JPA entities along with JAXB annotations.
Do not give the simple JPA #Id up. That's the heart of JPA.
#XmlRootElement
public class Parent {
#Id
#XmlAttribute
private Long id;
#OneToMany
#XmlElement(name = "child")
#XmlElementWrapper
private Collection<Child> children;
}
#XmlRootElement
public class Child {
#XmlAttribute
private Long getParentId() {
return parent.getId();
}
#Id
#XmlAttribute
private Long id;
#ManyToOne
#XmlTransient // for preventing infinite circular problem
private Parent parent;
}
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
WHAT THE ANSWER SHOULD BE
The answer should be to use the #XmlSchemaType annotation on both the #XmlID and #XmlIDREF properties. Unfortunately the JAXB RI does not leverage that combination, and EclipseLink MOXy only leverages it for #XmlID. I have entered the following MOXy bug, which we could fix if you are interested in this approach:
http://bugs.eclipse.org/386569
Employee
package forum11791735;
import java.util.List;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Employee {
#XmlID
#XmlJavaTypeAdapter(JAXBLongAdapter.class)
#XmlSchemaType(name="long")
private Long id;
#XmlIDREF
#XmlSchemaType(name="long")
private Employee manager;
#XmlElement(name="report")
private List<Employee> reports;
}
WORK AROUND
The error you are seeing is appears to be due to schema validation. Is it possible for you to disable schema validation or set a ValidationEventHandler on the Unmarshaller to ignore these errors?
http://blog.bdoughan.com/2010/12/jaxb-and-marshalunmarshal-schema.html
ALTERNATIVES
If you are using #XmlID/#XmlIDREF to map bidirectional relationships then you may be interested in MOXy's #XmlInverseReference extension:
http://blog.bdoughan.com/2010/07/jpa-entities-to-xml-bidirectional.html