I am trying to learn testing in Spring Boot. I was trying to test my models but then I faced with NullPointer. Let's see the code.
Genre.java
public class Genre {
#Column(nullable = false)
#OneToMany(mappedBy = "genre", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Movie> movieSet;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Set<Movie> getMovie() {
return movieSet;
}
public void setMovie(Movie movie) {
if (movieSet.size() == 0) {
movieSet = new HashSet<>();
}
movieSet.add(movie);
}}
GenreTest.java
public class GenreTest {
#Test
public void IdGetterSetter() {
Genre genre = new Genre();
genre.setId(1);
assertThat(genre.getId()).isEqualTo(1);
}
#Test
public void MovieGetterSetter(){
Genre genre = new Genre();
Movie movie = new Movie();
genre.setMovie(movie);
assertThat(genre.getMovie()).isEqualTo(movie);
}}
genre.setMovie(movie) is getting NullPointer error. What should I need to do? By the way, I am testing my getter and setter functions in the same function. Do I need to seperate them or is it okay to use it like that? Give me some opinion please.
This:
public void setMovie(Movie movie) {
if (movieSet.size() == 0) {
movieSet = new HashSet<>();
}
movieSet.add(movie);
}}
movieSet is unitialized.
You either want to:
private Set<Movie> movieSet = new HashSet<>();
Or:
public void setMovie(Movie movie) {
if (movieSet == null) {
movieSet = new HashSet<>();
}
movieSet.add(movie);
}}
Related
I am working on a small app where people can like posts they like, but I can't manage to do it. The backend sent a "Not-null property references a transient value" error which I tried to solve by adding "cascade = CascadeType.All" in the entities causing the issue, but when the data is saved, it also saves new items in child tables.
To be more precise, I have this Thumbsup item to save, which has 3 columns (and all 3 are foreign keys) : fk_account, fk_merch and fk_post. When saving the Thumbsup, it creates a Merch item and then saves its id in fk_merch, which I do not want here.
Here is my thumbsup.java :
#NoArgsConstructor
#AllArgsConstructor
#Entity
public class Thumbsup {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int thumbsupId;
#ManyToOne
#JoinColumn(name = "fk_post", referencedColumnName = "postId")
private Post post;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "fk_merch", nullable = true, referencedColumnName = "merchId")
private Merch merch;
#ManyToOne
#JoinColumn(name = "fk_account", nullable = false, referencedColumnName = "accountId")
private Account account;
public static class Builder {
int thumbsupId;
Post post;
Merch merch;
Account account;
public Builder setThumbsupId(int thumbsupId) {
this.thumbsupId = thumbsupId;
return this;
}
public Builder setPost(Post post) {
this.post = post;
return this;
}
public Builder setMerch(Merch merch) {
this.merch = merch;
return this;
}
public Builder setAccount(Account account) {
this.account = account;
return this;
}
public Thumbsup build() {
return new Thumbsup(thumbsupId, post, merch, account);
}
}
}
merch.java :
#NoArgsConstructor
#AllArgsConstructor
#Entity
public class Merch {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int merchId;
#NotNull
private String itemname;
#NotNull
private double itemprice;
private boolean active;
private Date creation_date;
private Date update_date;
private Date deletion_date;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "fk_artist", nullable = false, referencedColumnName = "artistId")
private Artist artist;
public static class Builder {
int merchId;
String itemname;
double itemprice;
boolean active;
Date creation_date = new Date();
Date update_date;
Date deletion_date;
Artist artist;
public Builder setMerchId(int merchId) {
this.merchId = merchId;
return this;
}
public Builder setItemname(String itemname) {
this.itemname = itemname;
return this;
}
public Builder setItemprice(double itemprice) {
this.itemprice = itemprice;
return this;
}
public Builder setActive(boolean active) {
this.active = active;
return this;
}
public Builder setCreation_date(Date creation_date) {
this.creation_date = creation_date;
return this;
}
public Builder setUpdate_date(Date update_date) {
this.update_date = update_date;
return this;
}
public Builder setDeletion_date(Date deletion_date) {
this.deletion_date = deletion_date;
return this;
}
public Builder setArtist(Artist artist) {
this.artist = artist;
return this;
}
public Merch build() {
return new Merch(merchId, itemname, itemprice ,active, creation_date, update_date, deletion_date, artist);
}
}
}
post-structure.component.ts :
export class PostStructureComponent implements OnInit {
#Input() post!: Post;
credential!: Credential;
accountDetail!: Account;
artist!: Artist;
selectedPost!: Post;
thumbsup!: Thumbsup;
thumbsups!: Thumbsup[];
postForm!: FormGroup;
constructor(public artistService: ArtistService,
public postService: PostService,
public thumbsupService: ThumbsupService,
public accountService: AccountService,
public auth: AuthService) {
}
ngOnInit(): void {
this.auth.me().subscribe((response: ApiResponse) => {
this.credential = CredentialHelper.credentialFromDto(response.data as CredentialDto);
this.accountService.getDetail(this.credential.account.accountId.toString()).subscribe((account: Account) => {
this.accountDetail = account;
this.artistService.getDetail(this.accountDetail.accountId.toString()).subscribe((artist: Artist) => {
this.artist = artist;
this.thumbsupService.getListByPost(this.post.postId.toString()).subscribe((thumbsups: Thumbsup[]) => {
this.thumbsups = thumbsups;
this.thumbsups.forEach(thumbsup => {
if (thumbsup.account.accountId == this.accountDetail.accountId){
this.thumbsup = thumbsup;
}
})
})
})
})
})
}
onLike():void {
let newThumbsup = {
thumbsupId: 0,
account: this.accountDetail,
merch: MerchHelper.empty(),
post: this.post
}
if (this.thumbsup == undefined ||this.thumbsup.thumbsupId == 0){
this.thumbsupService.create(ThumbsupHelper.returnCreatePayload(newThumbsup)).subscribe();
} else {
this.thumbsupService.deleteThumbsup(this.thumbsup.thumbsupId.toString()).subscribe();
}
}
}
thumbsup.helper.ts :
export class ThumbsupHelper {
public static empty(): Thumbsup {
return {
thumbsupId: 0,
account: AccountHelper.empty(),
merch: MerchHelper.empty(),
post: PostHelper.empty()
}
}
public static returnCreatePayload(thumbsup: Thumbsup): ThumbsupCreatePayload {
return {
account: thumbsup.account,
merch: thumbsup.merch,
post: thumbsup.post
}
}
I know that there are several and serious issues in my Angular code, such as getting credential, accountDetail and artist this way but I plan to modify this later, as well as . Also, I think that I should use Observables to manage data changes on thumbsup and evaluate if it exists or not to decide which method to call, but I have difficulties with it.
If anything is missing, I'll add it as soon as possible.
If you want to refer to entities that already exist, you will have to load them via EntityManager.find(Class entityClass, Object id) or get a proxy reference to the object via EntityManager.getReference(Class entityClass, Object id).
So instead of using CascadeType.ALL in Thumbsup, you will have to set the fields of the associations merch, post and account with the object returned by find or getReference.
Here's MVCE: https://github.com/neo4j-examples/movies-java-spring-data-neo4j
If you change one test to:
#Test
public void testFindByTitle() {
String title = "The Matrix";
Movie result = movieRepository.findByTitle(title);
Person p = personRepository.findByName("Keanu Reeves");
assertNotNull(result);
assertEquals(1999, result.getReleased());
}
You can see in debug mode that object p does not have any movies.
Person entity is:
#NodeEntity
public class Person {
#Id
#GeneratedValue
private Long id;
private String name;
private int born;
#Relationship(type = "ACTED_IN")
private List<Movie> movies = new ArrayList<>();
public Person() {
}
public Person(String name, int born) {
this.name = name;
this.born = born;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public int getBorn() {
return born;
}
public List<Movie> getMovies() {
return movies;
}
}
This is offical example from neo4j. How can i store entity Person with movies in database and also have Movie entity with roles ?
Edit: What i can do is add in Person entity method:
public void addMovie(Movie movie) {
if (this.movies == null) {
this.movies = new ArrayList<>();
}
this.movies.add(movie);
}
And in the test add:
p.addMovie(matrix);
personRepository.save(p);
But i don't like this - cause i setting it manually from two sites.
You do not need to set the references manually from two sides. Expand your code snippet slightly by a single line movie.setPerson(this); and you are done:
public void addMovie(#NotNull Movie movie) {
if (this.movies == null)
this.movies = new ArrayList<>();
this.movies.add(movie);
movie.setPerson(this);
}
I'm a student, new to Stack Overflow, spring-boot and hibernate stack.
The problem: return a list of questions based on their category id.
As the in my model entity classes below I have no attributes for categoryId(foreign key) as this is being generated automatically through the relationship annotations.
I seem to be able to return a list of all questions with no level of filtering, but would also like a method that returns the questions based on their category id(foreign key).
Any help would be greatly appreciated, Thanks!
Using hibernate 5.2
categoryModel
#Entity
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
#Size(min = 3, max = 20)
private String name;
#NotNull
#Pattern(regexp = "#[0-9a-fA-F]{6}")
private String colorCode;
#OneToMany(mappedBy = "category")
private List<Question> questions = new ArrayList<>();
public Category(){}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Question> getQuestions() {
return questions;
}
public String getColorCode() {
return colorCode;
}
public void setColorCode(String colorCode) {
this.colorCode = colorCode;
}
questionModel
#Entity
public class Question {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ManyToOne
private Category category;
private LocalDateTime dateCreated = LocalDateTime.now();
public Question(){}
public String getTimeSinceUploaded() {
String unit = "";
LocalDateTime now = LocalDateTime.now();
long diff;
if((diff = ChronoUnit.SECONDS.between(dateCreated,now)) < 60){
unit = "secs";
} else if ((diff = ChronoUnit.MINUTES.between(dateCreated,now)) < 60) {
unit = "mins";
} else if ((diff = ChronoUnit.HOURS.between(dateCreated,now)) < 24) {
unit = "hours";
} else if ((diff = ChronoUnit.DAYS.between(dateCreated,now)) < 30) {
unit = "days";
} else if ((diff = ChronoUnit.MONTHS.between(dateCreated,now)) < 12) {
unit = "months";
} else{
diff = ChronoUnit.YEARS.between(dateCreated,now);
}
return String.format("%d %s",diff,unit);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public LocalDateTime getDateCreated() {
return dateCreated;
}
public void setDateCreated(LocalDateTime dateCreated) {
this.dateCreated = dateCreated;
}
}
question DAO
#Repository
public class QuestionDaoImpl implements IQuestionDao {
#Autowired
private SessionFactory sessionFactory;
/**
* Returns a list of all the questions - michael
*/
#Override
public List<Question> findAll() {
Session session = sessionFactory.openSession();
// Create CriteriaBuilder
CriteriaBuilder builder = session.getCriteriaBuilder();
// Create CriteriaQuery
CriteriaQuery<Question> criteria = builder.createQuery(Question.class);
// Specify criteria root
criteria.from(Question.class);
// Execute query
List<Question> questions = session.createQuery(criteria).getResultList();
session.close();
return questions;
}
/**
* Returns A question by using the id - michael
*/
#Override
public Question findById(Long id) {
Session session = sessionFactory.openSession();
Question question = session.get(Question.class, id);
session.close();
return question;
}
/**
* TODO: ml- Finds a list of questions according to the category_id
*/
#Override
public List<Question> findByCategoryId(Long categoryId){
// This is a issue i a have here
return null;
}
try this, you have to pass category object bcz you created object in question entity,
#Override
public List<Question> findByCategoryId(Long categoryId){
Session session = sessionFactory.openSession();
final Criteria cr = session.createCriteria(Question.class);
cr.add(Restrictions.eq("category", category));
return cr.list();
}
Let me know if any quires.
Is your Dao extends crudrepository or JpaRepository?
public User updateUser(User user) {
try {
User result = session.get(User.class, user.getId());
if (result == null) {
throw new FilamentNoSuchRecordException(new CoreError(304, "User does not exist"));
}
session.clear();
session.update(user);
return user;
} catch (HibernateException e) {
e.printStackTrace();
}
throw new FilamentDataConnectivityException(new CoreError(305,"Connectivity issue. Please see System Administrator"));
}
customer model is as follows
#Entity
#Table(name = "customers")
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
#DynamicUpdate(value=true)
#SelectBeforeUpdate(value=true)
#SQLDelete(sql="Update customers SET deleted = true where customer_id=?")
#Where(clause="deleted != true")
#ApiModel(description="Create or update Customers")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Customer {
#Id
#Column(name="customer_id")
#NotNull
#GeneratedValue(strategy=GenerationType.AUTO)
private int id = 0;
#Column(name="name")
#ApiModelProperty(value="The name of the customer", example="Mr J. Bond")
#NotNull
private String name;
#Column(name="description")
#ApiModelProperty(value="Desciption of the customer")
#NotNull
private String description;
#Column(name="logo_url")
#ApiModelProperty(value="Logo of user")
#NotNull
private String logo;
#Column(name="created_at")
#ApiModelProperty(value="The date the item was created", example="")
#NotNull
private Date createdAt;
#Column(name="updated_at")
#ApiModelProperty(value="The date the item was updated", example="")
#NotNull
private Date updatedAt;
#ApiModelProperty(hidden=true)
#OneToMany(fetch = FetchType.LAZY, mappedBy = "customer")
private Set<Application> applications = new HashSet<Application>();
#ManyToMany(mappedBy = "customers")
private Set<Service> services = new HashSet<Service>();
#ApiModelProperty(hidden=true)
#OneToMany(fetch = FetchType.LAZY, mappedBy = "customer")
private Set<User> users = new HashSet<User>();
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(
name = "customer_subscription",
joinColumns = #JoinColumn(name = "customer_id"),
inverseJoinColumns = #JoinColumn(name = "subscription_id")
)
private Set<Subscription> subscriptions = new HashSet<Subscription>();
#ApiModelProperty(hidden=true)
#OneToMany(fetch = FetchType.LAZY, mappedBy = "customer")
private Set<Corpus> corpus = new HashSet<Corpus>();
#Column(name="deleted")
#NotNull
private boolean deleteFlag;
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 Set<Application> getApplications() {
return applications;
}
public void setApplications(Set<Application> applications) {
this.applications = applications;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getLogo() {
return logo;
}
public void setLogo(String logo) {
this.logo = logo;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public Date getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
public Set<Service> getServices() {
return services;
}
public void setServices(Set<Service> services) {
this.services = services;
}
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
public Set<Corpus> getCorpus() {
return corpus;
}
public void setCorpus(Set<Corpus> corpus) {
this.corpus = corpus;
}
public Set<Subscription> getSubscriptions() {
return subscriptions;
}
public void setSubscriptions(Set<Subscription> subscriptions) {
this.subscriptions = subscriptions;
}
public boolean getDeleteFlag() {
return deleteFlag;
}
public void setDeleteFlag(boolean deleteFlag) {
this.deleteFlag = deleteFlag;
}
}
I check whether the object exists within the database, then update with an object, for example all fields could be null apart from the ID and the one thats needs to be updated. All fields are set to #NotNull in the model and I am using the #DynamicUpdate(value=true) and #SelectBeforeUpdate(value=true) annotations, but these seem to do nothing.
Just get failure saying the null fields can not be null. How do I update the row?
As we discussed in above comments, try this -
public User updateUser(User user) {
try {
User result = session.get(User.class, user.getId());
if (result == null) {
throw new FilamentNoSuchRecordException(new CoreError(304, "User does not exist"));
}
result.setName(user.getName()); // update some properties
session.update(result); // you should update 'result', not 'user'
return result;
} catch (HibernateException e) {
e.printStackTrace();
throw new FilamentDataConnectivityException(new CoreError(305,"Connectivity issue. Please see System Administrator"));
}
}
By using this method I found in another stack overflow post solved the issue. This checks each field and uses the 'not null' value. Then i can update from an object with only 1 field changed.
public static <T> T getNotNull(T a, T b) {
return b != null && a != null && !a.equals(b) ? a : b;
}
I'm trying to get a list of objects from database using Hibernate but something seems weird for me.
In the DB I have 5 Runs with 3 Positions each.
When I get the List of runs from RunDao I obtain a list of 15 Run objects ! The three first runs have the same ID.
In my case I just want to get the 5 Runs. Am I doing something wrong ?
How to get only the 5 runs ?
Thanks a lot
Here are my classes Run / Position / RunDao :
Run.java
#Entity
#Table(name="kr_runs")
public class Run {
private long id;
private Date date;
private int indexedPages;
private int pr;
#JsonIgnore
private Site site;
private Set<Position> positions = new HashSet<Position>(0);
public Run() {
}
#Id
#GeneratedValue
#Column(name="id")
public long getId() {
return id;
}
public void setId( long id ) {
this.id = id;
}
#Temporal(value=TemporalType.TIMESTAMP)
public Date getDate() {
return date;
}
public void setDate( Date date ) {
this.date = date;
}
#Column(name="indexed_pages")
public int getIndexedPages() {
return indexedPages;
}
public void setIndexedPages( int indexedPages ) {
this.indexedPages = indexedPages;
}
#Column
public int getPr() {
return pr;
}
public void setPr( int pr ) {
this.pr = pr;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "kr_site_id", nullable = false)
public Site getSite() {
return site;
}
public void setSite( Site site ) {
this.site = site;
}
#Cascade({CascadeType.ALL})
#OneToMany(fetch = FetchType.EAGER, mappedBy = "run")
public Set<Position> getPositions() {
return positions;
}
public void setPositions( Set<Position> positions ) {
this.positions = positions;
}
}
Position.java
#Entity
#Table(name="kr_positions")
public class Position {
private long id;
private int pos;
private String url;
#JsonIgnore
private Run run;
private Keyword keyword;
public Position() {
}
#Id
#GeneratedValue
#Column(name="id")
public long getId() {
return id;
}
public void setId( long id ) {
this.id = id;
}
#Column
public int getPos() {
return pos;
}
public void setPos( int pos ) {
this.pos = pos;
}
#Column
public String getUrl() {
return url;
}
public void setUrl( String url ) {
this.url = url;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "kr_run_id", nullable = false)
public Run getRun() {
return run;
}
public void setRun( Run run ) {
this.run = run;
}
//#Cascade({CascadeType.SAVE_UPDATE})
//#OneToOne(mappedBy="position")
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "kr_keyword_id", nullable = false)
public Keyword getKeyword() {
return keyword;
}
public void setKeyword( Keyword keyword ) {
this.keyword = keyword;
}
}
RunDao.java
#Transactional
public class RunDao extends HibernateDao<Run, Long> implements IRunDao {
public List<Run> find( long siteID, Date date_start, Date date_end ) {
Criteria cr = currentSession().createCriteria(Run.class);
cr.add(Restrictions.eq("site.id", siteID));
cr.add(Restrictions.ge("date",date_start));
cr.add(Restrictions.lt("date",date_end));
List<Run> list = (List<Run>) cr.list();
if (list.isEmpty()) return null;
else return list;
}
}
Solved
Thanks to the help of Guillaume I found a solution.
I replaced in the Run class :
#OneToMany(fetch = FetchType.EAGER, mappedBy = "run")
by
#OneToMany(fetch = FetchType.LAZY, mappedBy = "run")
In my RunsService class when I get the Runs from DAO I pull the lazy collection :
// Get data from DAO
List<Run> list = runDao.find(siteID, cal.getTime(), date_today);
for(Run run : list)
{
Hibernate.initialize(run.getPositions()); // run.getPositions().size(); if you are note in #Transactional
}
Everything in your code looks correct. The only thing I'm not too certain about #OneToMany(fetch = FetchType.EAGER ... since I've had bugs in the past with EAGER fetch types.
Try to leave it LAZY and add a fetch join in your criteria query instead.