JPA cannot fill entries in join table - java

I'm trying to map a bidirectional ManyToMany relationship between the class Problem and the class Domain. Therefore the persistency unit creates a join table in the database, but it seems no entry pops up in the database.
Here's some code:
The class Problem
package domain;
import java.io.Serializable;
import java.util.List;
import javax.persistence.*;
import static javax.persistence.GenerationType.SEQUENCE;
import javax.xml.bind.annotation.XmlRootElement;
#Entity
#XmlRootElement
public class Problem implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private User user;
private String description;
private int maxprice;
private int priority;
private Solution solution;
private Location location;
private List<Domain> domains;
#Id
//#GeneratedValue(strategy = GenerationType.AUTO)
#SequenceGenerator(name="User_Seq", allocationSize=25)
#GeneratedValue(strategy=SEQUENCE, generator="Problem_Seq")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#ManyToOne
//#JoinColumn(name="user_id")
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getMaxPrice() {
return maxprice;
}
public void setMaxPrice(int maxprice) {
this.maxprice = maxprice;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="solution_id")
public Solution getSolution() {
return solution;
}
public void setSolution(Solution solution) {
this.solution = solution;
}
#ManyToOne
#JoinColumn(name="location_id")
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
#ManyToMany
#JoinTable(name="problem_domain",
joinColumns={#JoinColumn(name="problem_id", referencedColumnName="ID")},
inverseJoinColumns={#JoinColumn(name="domain_id", referencedColumnName="ID")})
public List<Domain> getDomains() {
return domains;
}
public void setDomains(List<Domain> domains) {
this.domains = domains;
}
public void addDomain(Domain domain){
//this.domains.add(domain); //Throws NullpointerException om een of andere reden.
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Problem)) {
return false;
}
Problem other = (Problem) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "domain.Problem[ id=" + id + " ]";
}
}
The class Domain
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package domain;
import java.io.Serializable;
import java.util.List;
import javax.persistence.*;
import static javax.persistence.GenerationType.SEQUENCE;
import javax.xml.bind.annotation.XmlRootElement;
#Entity
#XmlRootElement
public class Domain implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private List<Problem> problems;
private List<Domain> subDomains;
private Domain superDomain;
#Id
#SequenceGenerator(name="Dom_Seq", allocationSize=25)
#GeneratedValue(strategy=SEQUENCE, generator="Dom_Seq")
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;
}
#ManyToMany(mappedBy = "domains")
public List<Problem> getProblems() {
return problems;
}
public void setProblems(List<Problem> problems) {
this.problems = problems;
}
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinColumn(name="superdomain_id")
public List<Domain> getSubDomains() {
return subDomains;
}
public void setSubDomains(List<Domain> subDomains) {
this.subDomains = subDomains;
}
public Domain getSuperDomain() {
return superDomain;
}
public void setSuperDomain(Domain superDomain) {
this.superDomain = superDomain;
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Domain)) {
return false;
}
Domain other = (Domain) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "domain.Domain[ id=" + id + " ]";
}
}
the code where we add a problem and a domain to the database
Problem problem = new Problem();
Domain domain = new Domain();
domain.setName(domainString);
domainFacade.create(domain);
problemFacade.create(problem);
problem.addDomain(domain);
problemFacade.edit(problem);
and a little visual explanation of the DB

Do you try to save List of domain to problem?
Example of code:
Problem problem = new Problem();
Domain domain = new Domain();
domain.setName(domainString);
domainFacade.create(domain);
List<Domain> domains = new ArrayList<Domain>();
domains.add(domain);
problem.setDomains(domains);
problemFacade.create(problem);

As #Neil Stockton and others said, the answer to my problem was that I had to have an addMethod that simply added the object to the list.

Related

Hibernate - Column cannot be null

I'm doing a simple exercise to learn JPA.
When I try to delete an entity of type User, which has a Collection of the other entity Score (annotated with #OneToMany) I get this error:
java.sql.SQLIntegrityConstraintViolationException: Column 'user' cannot be null
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1092)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1040)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1347)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1025)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
... 20 more
These are my classes:
User.java
#Entity
#Table(name = "user")
public class User
{
#Id
private Integer id;
#NotNull
#Size(max = 20)
private String name;
#OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL,orphanRemoval = true)
#JoinColumn(name = "user")
private Collection<Score> scores;
public User() {
}
public User(Integer id, String name, Collection<Score> scores) {
this.id = id;
this.name = name;
this.scores = scores;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Collection<Score> getScores() {
return scores;
}
public void setScores(Collection<Score> scores) {
this.scores = scores;
}
}
Score.java
#Entity
#Table(name = "score")
public class Score
{
#EmbeddedId
private ScoreId id;
#NotNull
private Integer points;
public Score() {
}
public Score(ScoreId id, Integer points) {
this.id = id;
this.points = points;
}
public ScoreId getId() {
return id;
}
public void setId(ScoreId id) {
this.id = id;
}
public Integer getPoints() {
return points;
}
public void setPoints(Integer points) {
this.points = points;
}
#Override
public boolean equals(Object obj) {
if (obj!=null && getClass()==obj.getClass())
{
Score other = (Score) obj;
return Objects.equals(id, other.id) && Objects.equals(points,other.points);
}
return false;
}
#Override
public int hashCode() {
return id!=null ? points!=null ? id.hashCode()+points.hashCode() : 0 : 0;
}
#Override
public String toString() {
return getClass().getName() + "[id =" + id + ",points = " + points;
}
}
ScoreId.java
#Embeddable
public class ScoreId implements Serializable
{
private Integer user;
#Enumerated(EnumType.STRING)
private Game game;
public ScoreId() {
}
public ScoreId(Integer user, Game game) {
this.user = user;
this.game = game;
}
public Integer getUser() {
return user;
}
public void setUser(Integer user) {
this.user = user;
}
public Game getGame() {
return game;
}
public void setGame(Game game) {
this.game = game;
}
public enum Game
{
HANGMAN,
TRIS
}
#Override
public boolean equals(Object obj) {
if (obj!=null && getClass()==obj.getClass())
{
ScoreId other = (ScoreId) obj;
return Objects.equals(user,other.user) && game==other.game;
}
return false;
}
#Override
public int hashCode()
{
return user!=null ? game!=null ? user.hashCode()+game.hashCode() : 0 : 0;
}
#Override
public String toString() {
return getClass().getName() + "[user = " + user + ",game = " + game + "]";
}
}
Main.java
public class Main {
public static void main(String[] args) {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("UserJPA");
EntityManager em = factory.createEntityManager();
EntityTransaction et = em.getTransaction();
User demetrio = em.createQuery("SELECT u FROM User u WHERE u.name = 'Demetrio'",User.class).getSingleResult();
et.begin();
em.remove(demetrio);
et.commit();
em.close();
factory.close();
}
}
This is the script to generate db:
CREATE TABLE `user`
(
id INT PRIMARY KEY,
`name` VARCHAR(20) UNIQUE NOT NULL
);
CREATE TABLE score
(
`user` INT,
game ENUM("HANGMAN","TRIS"),
points INT UNSIGNED NOT NULL,
PRIMARY KEY(`user`,game),
FOREIGN KEY (`user`) REFERENCES `user`(id)
ON UPDATE CASCADE
ON DELETE CASCADE
)
I'm using Hibernate as JPA implementation.
I searched for a solution but I did not find anything.
Maybe I'm doing something wrong.
Can you help me?
The implementation I see is absolutly correct, allthou it always can be improoved. The db-design is good. The exception you post can simply not exist but it does. The Database must have a problem. Thats why I asked to post the DDL of the table. I trust in your DDL you posted what makes me think: You did everything right.
What I do is I could only guess.
The table's engine is InnoDB but what is the status of the InnoDB-engine? Is it working? Is it active? Use SHOW ENGINE INNODB STATUS to see the status of InnoDB.
I solved by replacing Integer user of ScoreId with User user with a #ManyToOne annotation.
These are my classes:
User.java
#Entity
#Table(name = "user")
public class User
{
#Id
private Integer id;
#NotNull
#Size(max = 20)
private String name;
#OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL,orphanRemoval = true,mappedBy = "id.user")
private Collection<Score> scores;
public User() {
}
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Collection<Score> getScores() {
return scores;
}
public void setScores(Collection<Score> scores) {
this.scores = scores;
}
#Override
public boolean equals(Object obj) {
if (obj!=null && getClass()==obj.getClass())
{
User other = (User) obj;
return Objects.equals(id, other.id) && Objects.equals(name, other.name);
}
return false;
}
#Override
public String toString() {
return getClass().getName() + "[id = " + id + ",name = " + name + "]";
}
#Override
public int hashCode() {
return id!=null ? name!=null ? id.hashCode() + name.hashCode() : 0 : 0;
}
}
Score.java
#Entity
#Table(name = "score")
public class Score
{
#EmbeddedId
private ScoreId id;
#NotNull
private Integer points;
public Score() {
}
public Score(ScoreId id, Integer points) {
this.id = id;
this.points = points;
}
#Override
public boolean equals(Object obj) {
if (obj!=null && getClass()==obj.getClass())
{
Score other = (Score) obj;
return Objects.equals(id,other.id) && Objects.equals(points,other.points);
}
return false;
}
#Override
public int hashCode() {
return id!=null ? points!=null ? id.hashCode()+points.hashCode() : 0 : 0;
}
#Override
public String toString() {
return getClass().getName() + "[id =" + id + ",points = " + points + "]";
}
}
ScoreId.java
#Embeddable
public class ScoreId implements Serializable
{
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="user",referencedColumnName = "id")
private User user;
#Enumerated(EnumType.STRING)
private Game game;
public ScoreId() {
}
public ScoreId(User user, Game game) {
this.user = user;
this.game = game;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Game getGame() {
return game;
}
public void setGame(Game game) {
this.game = game;
}
public enum Game
{
HANGMAN,
TRIS
}
#Override
public boolean equals(Object obj) {
if (obj!=null && getClass()==obj.getClass())
{
ScoreId other = (ScoreId) obj;
return Objects.equals(user,other.user) && game==other.game;
}
return false;
}
#Override
public int hashCode()
{
return user!=null ? game!=null ? user.hashCode()+game.hashCode() : 0 : 0;
}
#Override
public String toString() {
return getClass().getName() + "[user = " + user + ",game = " + game + "]";
}
}
Database schema is the same.
In my case there was an Envers used, and on deleteAll() or delete() it tried to insert a record with type 2 (deleted) into corresponding _aud table.
However, when it does so, all the fields of the record appear to be NULL, but in the _aud table one of the columns was marked as "NON-NULL".
Removing the "NON-NULL" from those column in _aud table fixed the issue.

Spring data Cassandra #Indexed annotation

I was working on Spring data Cassandra While creating an entity I am giving the required annotations for fields but when I am giving #Indexed annotation for creating an secondary index in the Schema and I am not able to query on the indexed attribute with out giving Allow Filtering.Could some one please tell me how to create a Secondary Index using Spring data annotations in Cassandra
This is the sample cod that I am using creating a Sprind data Cassandra Entity.#Indexed annotation not creating a secondary index in Cassandra database
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import org.springframework.data.cassandra.mapping.CassandraType;
import org.springframework.data.cassandra.mapping.Column;
import org.springframework.data.cassandra.mapping.Indexed;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.Table;
import org.springframework.data.cassandra.mapping.UserDefinedType;
import com.datastax.driver.core.DataType;
import com.suntecgroup.xelerate.platform.demo.config.SpringContainer;
import com.suntecgroup.xelerate.platform.demo.store.CustomerCassandraStore;
import com.suntecgroup.xelerate.platform.demo.store.impl.CustomerCassandraStoreImpl;
#Table(value="CustomerCassandra")
public class CustomerCassandra extends CassandraEntity<Integer> {
#PrimaryKey(value="cust_id")
private Integer custId;
#Indexed(value="name")
private String name;
#Indexed(value="email")
private String email;
#Column(value="domain")
private String domain;
#Column(value="category")
private String category;
#Column(value="created_at")
private Date createdAt;
#CassandraType(type=DataType.Name.LIST,typeArguments = { DataType.Name.UDT }, userTypeName = "address_demo_type")
#Column(value="addresses")
private List<Address> addresses;
#Override
public Integer getId() {
return custId;
}
#Override
public void setId(Integer id) {
this.custId = id;
}
public static CustomerCassandraStore getStore() {
return (CustomerCassandraStore) SpringContainer.getBean(CustomerCassandraStoreImpl.class);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public List<Address> getAddresses() {
return addresses;
}
public void setAddresses(Address... addresses) {
LinkedList<Address> addressList = new LinkedList<>();
for(Address addr: addresses) {
addressList.add(addr);
}
setAddresses(addressList);
}
public void setAddresses(List<Address> addresses) {
this.addresses = addresses;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
#UserDefinedType(value="address_demo_type")
public static class Address {
#CassandraType(type = DataType.Name.TEXT)
#Column(value="street_address")
private String streetAddress;
#CassandraType(type = DataType.Name.TEXT)
#Column(value="city")
private String city;
#CassandraType(type = DataType.Name.TEXT)
#Column(value="country")
private String country;
#CassandraType(type = DataType.Name.TEXT)
#Column(value="pincode")
private String pincode;
public String getStreetAddress() {
return streetAddress;
}
public void setStreetAddress(String streetAddress) {
this.streetAddress = streetAddress;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getPincode() {
return pincode;
}
public void setPincode(String pincode) {
this.pincode = pincode;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((city == null) ? 0 : city.hashCode());
result = prime * result + ((country == null) ? 0 : country.hashCode());
result = prime * result + ((pincode == null) ? 0 : pincode.hashCode());
result = prime * result
+ ((streetAddress == null) ? 0 : streetAddress.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Address other = (Address) obj;
if (city == null) {
if (other.city != null)
return false;
} else if (!city.equals(other.city))
return false;
if (country == null) {
if (other.country != null)
return false;
} else if (!country.equals(other.country))
return false;
if (pincode == null) {
if (other.pincode != null)
return false;
} else if (!pincode.equals(other.pincode))
return false;
if (streetAddress == null) {
if (other.streetAddress != null)
return false;
} else if (!streetAddress.equals(other.streetAddress))
return false;
return true;
}}
}
It looks like some bug in spring-data-cassandra lib. I'm not able to create index through annotation as well.
I faced a similar issue while creating the schema during test execution (it's not clear how the OP creates the table based on the annotations).
My code was invoking CassandraAdminOperations.createTable() function and I quickly found out that createTable does not include indices, so any queries on the (supposedly) indexed columns were failing. My original code was just:
#Autowired
private CassandraAdminOperations adminTemplate;
#Before
public void createTable() {
adminTemplate.createTable(true, CqlIdentifier.of(DATA_TABLE_NAME), User.class, new HashMap<>());
}
In order to generate the indices based on the annotations, I had to modify my #Before method as:
#Autowired
private CassandraAdminOperations adminTemplate;
#Before
public void createTable() {
adminTemplate.createTable(true, CqlIdentifier.of(DATA_TABLE_NAME), User.class, new HashMap<>());
CassandraPersistentEntity<?> entity = adminTemplate.getConverter().getMappingContext().getRequiredPersistentEntity(User.class);
List<CreateIndexSpecification> indexSpecifications = adminTemplate.getConverter().getMappingContext().getCreateIndexSpecificationsFor(entity);
indexSpecifications.forEach(is -> adminTemplate.getCqlOperations().execute((CreateIndexCqlGenerator.toCql(is))));
}
Table tableAnno=AnnotationUtils.getAnnotation(MessagePO.class, Table.class);
String tableName=tableAnno.value();
log.info("initial table{}",tableName);
/**
* create table
*/
adminTemplate.createTable(true, CqlIdentifier.fromCql(tableName), MessagePO.class, null);
Field[] fields = MessagePO.class.getDeclaredFields();
/**
* create index
*/
CqlOperations cqlOperations=adminTemplate.getCqlOperations();
Arrays.stream(fields).forEach(field -> {
Indexed indexed = AnnotationUtils.getAnnotation(field, Indexed.class);
Column column = AnnotationUtils.getAnnotation(field, Column.class);
if (indexed != null && column != null) {
String indexVal = indexed.value();
String indexSql=String.format("CREATE INDEX %s on %s(%s)",indexVal,tableName,column.value());
cqlOperations.execute(String.format("DROP INDEX if EXISTS %s",indexVal));
cqlOperations.execute(indexSql);
log.info("create index {}",indexSql);
}
});
this is my initial index code, it's work well

JPA query for one to one relation

I have an EJB application in where I am using Entity beans for database. I have to Entity beans having unidirectional one to one relation, JobPositionEntity and CandidateEntity.
Here is CandidateEntity
#Entity
public class CandidateEntity extends BaseEntity {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Long meritNumber;
private String seatNumber;
private String candidateName;
private String gender;
public Long getMeritNumber() {
return meritNumber;
}
public void setMeritNumber(Long meritNumber) {
this.meritNumber = meritNumber;
}
public String getSeatNumber() {
return seatNumber;
}
public void setSeatNumber(String seatNumber) {
this.seatNumber = seatNumber;
}
public String getCandidateName() {
return candidateName;
}
public void setCandidateName(String candidateName) {
this.candidateName = candidateName;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
#Override
public Long getId() {
return id;
}
#Override
public void setId(Long id) {
this.id = id;
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof CandidateEntity)) {
return false;
}
CandidateEntity other = (CandidateEntity) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "com.nisheeth.config.ejb.entity.CandidateEntity[ id=" + id + " ]";
}
}
Here is JobPositionEntity
#Entity
public class JobPositionEntity extends BaseEntity {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToOne(fetch = FetchType.EAGER, orphanRemoval = true, cascade = CascadeType.ALL)
private CandidateEntity candidate;
#ManyToOne(fetch = FetchType.EAGER)
private SeasonEntity season;
public SeasonEntity getSeason() {
return season;
}
public void setSeason(SeasonEntity season) {
this.season = season;
}
public CandidateEntity getCandidate() {
return candidate;
}
public void setCandidate(CandidateEntity candidate) {
this.candidate = candidate;
}
#Override
public Long getId() {
return id;
}
#Override
public void setId(Long id) {
this.id = id;
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof JobPositionEntity)) {
return false;
}
JobPositionEntity other = (JobPositionEntity) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "com.nisheeth.config.ejb.entity.JobPositionEntity[ id=" + id + " ]";
}
}
I want to select candidates which are not in JobPositionEntity. I have this query which did not work for me:
select ce.candidateName, ce.id from JobPositionEntity jp left join jp.candidate ce where ce <> null
Can anyone help write this query? Thanks in advance.
you can use a SubQuery
select c from Candidate c where c.id not in
(select jp.candidate.id from JobPositionEntity jp)
for more information:
https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.html#queryhql-subqueries

JPA CDI JAXB - Setter getting ignored

My JAX-RS Resource is successfully getting a JPA/JAXB entity and a list of JPA/JAXB entities from a db.
One entity serves as a parent entity. The list of entities is a field in the parent entity. I can't set the parent entity's list to the returned list of entities. The parent entity is returned in a JAXB parent entity, but that doesn't affect the situation.
Here's the code:
#Inject
InventoryService inventoryService;
#Inject
HcUser user;
#Inject
InventoryResponse inventoryResponse;
#GET
#Produces(MediaType.APPLICATION_JSON)
public InventoryResponse getInventory(#Context HttpServletRequest request,
#HeaderParam(IDENTITY_URL) String identityURL,
#HeaderParam(ACCESS_TOKEN) String accessToken) {
String username = (String) request.getAttribute("username");
user = inventoryService.getUserById(username);
user.setHcCounts(inventoryService.getCountsForUserId(username));
inventoryResponse.setUser(user);
return inventoryResponse;
}
The returned JSON is only returning the user object. I've tried manually instantiating a user object and setting it to the return value of the getUserById method and then calling setHcCounts with the returned list. However, the setter is still ignored.
What am I doing wrong?
I'm using WAS v8.0.0.8. The stack is:
JAX-RS - Apache Wink v1.1.1 (supplied by WAS 8)
OpenJPA - Apache v2.1.2-SNAPSHOT (supplied by WAS 8)
JAXB - MOXy v2.7
CDI - Apache OpenWebBeans 1.0 (supplied by WAS 8)
EJB - Apache OpenEJB (supplied by WAS 8)
Update 1
Here's the InventoryResponse class as requested, however I don't think that it's necessary. Upon inspecting the user object, on the line before inventoryResonse.setUser(user), during debugging, hcCounts is null.
#Named
#RequestScoped
#XmlRootElement
public class InventoryResponse implements Serializable {
private static final long serialVersionUID = 1L;
#Inject
private HcUser user;
private List<HcLocation> locations;
public HcUser getUser() {
return user;
}
public void setUser(HcUser user) {
this.user = user;
}
public List<HcLocation> getLocations() {
return locations;
}
public void setLocations(List<HcLocation> locations) {
this.locations = locations;
}
}
Update 2
As requested, HcUser:
import java.io.Serializable;
import javax.inject.Named;
import javax.persistence.*;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.Date;
import java.util.List;
#Entity
#Table(schema="<ommitted>", name="<ommitted>")
#Named
#XmlRootElement
public class HcUser implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(unique=true, nullable=false, length=100)
private String id;
#Column(nullable=false, length=1)
private boolean active;
#Temporal(TemporalType.DATE)
#Column(name="CREATE_DATE")
private Date createDate;
#Column(name="FIRST_NAME", length=100)
private String firstName;
#Column(name="LAST_NAME", length=100)
private String lastName;
#Temporal(TemporalType.DATE)
#Column(name="UPDATE_DATE")
private Date updateDate;
//bi-directional many-to-one association to HcAssignment
#OneToMany(mappedBy="hcUser")
#XmlElement
private List<HcAssignment> hcAssignments;
//bi-directional many-to-one association to HcCount
#OneToMany(mappedBy="hcUser")
#XmlElement
private List<HcCount> hcCounts;
public HcUser() {
}
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public boolean getActive() {
return this.active;
}
public void setActive(boolean active) {
this.active = active;
}
public Date getCreateDate() {
return this.createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return this.lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Date getUpdateDate() {
return this.updateDate;
}
public void setUpdateDate(Date updateDate) {
this.updateDate = updateDate;
}
public List<HcAssignment> getHcAssignments() {
return this.hcAssignments;
}
public void setHcAssignments(List<HcAssignment> hcAssignments) {
this.hcAssignments = hcAssignments;
}
public HcAssignment addHcAssignment(HcAssignment hcAssignment) {
getHcAssignments().add(hcAssignment);
hcAssignment.setHcUser(this);
return hcAssignment;
}
public HcAssignment removeHcAssignment(HcAssignment hcAssignment) {
getHcAssignments().remove(hcAssignment);
hcAssignment.setHcUser(null);
return hcAssignment;
}
public List<HcCount> getHcCounts() {
return this.hcCounts;
}
public void setHcCounts(List<HcCount> hcCounts) {
this.hcCounts = hcCounts;
}
public HcCount addHcCount(HcCount hcCount) {
getHcCounts().add(hcCount);
hcCount.setHcUser(this);
return hcCount;
}
public HcCount removeHcCount(HcCount hcCount) {
getHcCounts().remove(hcCount);
hcCount.setHcUser(null);
return hcCount;
}
/* (non-Javadoc)
* #see java.lang.Object#hashCode()
*/
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
/* (non-Javadoc)
* #see java.lang.Object#equals(java.lang.Object)
*/
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof HcUser)) {
return false;
}
HcUser other = (HcUser) obj;
if (id == null) {
if (other.id != null) {
return false;
}
} else if (!id.equals(other.id)) {
return false;
}
return true;
}
}
Update 3
Here's the code for HcCount:
import java.io.Serializable;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.*;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlInverseReference;
import java.math.BigDecimal;
import java.util.Date;
#Entity
#Table(schema="<omitted>", name="<omitted>")
#Named
#XmlRootElement
public class HcCount implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name="HC_COUNT_ID_GENERATOR", sequenceName="COUNT_SEQ")
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="HC_COUNT_ID_GENERATOR")
#Column(unique=true, nullable=false)
private long id;
#Column(name = "LOCATION_NUM", nullable = false, length = 100)
private String locationNum;
#Column(name = "PRODUCT_CODE", nullable = false, length = 100)
private String productCode;
#Column(name = "USER_ID", nullable = false, length = 100)
private String userId;
#Column(name = "LOT_CODE", nullable = false, length = 100)
private String lotCode;
#Column(name="\"COUNT\"")
private BigDecimal count;
#Temporal(TemporalType.DATE)
#Column(name="COUNT_DATE", unique=true, nullable=false)
private Date countDate;
#Temporal(TemporalType.DATE)
#Column(name="CREATE_DATE")
private Date createDate;
#Temporal(TemporalType.DATE)
#Column(name="UPDATE_DATE")
private Date updateDate;
//bi-directional many-to-one association to HcUser
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="USER_ID", unique=true, nullable=false)
#XmlElement
#XmlInverseReference(mappedBy="hcCounts")
#Inject private HcUser hcUser;
//bi-directional many-to-one association to HcLocation
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="LOCATION_NUM", referencedColumnName="NUM", unique=true, nullable=false)
#XmlElement
#XmlInverseReference(mappedBy="hcCounts")
#Inject private HcLocation hcLocation;
//bi-directional many-to-one association to HcProduct
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="PRODUCT_CODE", referencedColumnName="CODE_ID", unique=true, nullable=false)
#XmlElement
#XmlInverseReference(mappedBy="hcCounts")
#Inject private HcProduct hcProduct;
//bi-directional many-to-one association to HcLot
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="LOT_CODE", referencedColumnName="CODE_ID", unique=true, nullable=false)
#XmlElement
#XmlInverseReference(mappedBy="hcCounts")
#Inject private HcLot hcLot;
public HcCount() {
}
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
public String getLocationNum() {
return locationNum;
}
public void setLocationNum(String locationNum) {
this.locationNum = locationNum;
}
public String getProductCode() {
return productCode;
}
public void setProductCode(String productCode) {
this.productCode = productCode;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getLotCode() {
return lotCode;
}
public void setLotCode(String lotCode) {
this.lotCode = lotCode;
}
public BigDecimal getCount() {
return this.count;
}
public void setCount(BigDecimal count) {
this.count = count;
}
public Date getCountDate() {
return this.countDate;
}
public void setCountDate(Date countDate) {
this.countDate = countDate;
}
public Date getCreateDate() {
return this.createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public Date getUpdateDate() {
return this.updateDate;
}
public void setUpdateDate(Date updateDate) {
this.updateDate = updateDate;
}
public HcUser getHcUser() {
return this.hcUser;
}
public void setHcUser(HcUser hcUser) {
this.hcUser = hcUser;
}
public HcLocation getHcLocation() {
return this.hcLocation;
}
public void setHcLocation(HcLocation hcLocation) {
this.hcLocation = hcLocation;
}
public HcProduct getHcProduct() {
return this.hcProduct;
}
public void setHcProduct(HcProduct hcProduct) {
this.hcProduct = hcProduct;
}
public HcLot getHcLot() {
return this.hcLot;
}
public void setHcLot(HcLot hcLot) {
this.hcLot = hcLot;
}
/* (non-Javadoc)
* #see java.lang.Object#hashCode()
*/
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (id ^ (id >>> 32));
return result;
}
/* (non-Javadoc)
* #see java.lang.Object#equals(java.lang.Object)
*/
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof HcCount)) {
return false;
}
HcCount other = (HcCount) obj;
if (id != other.id) {
return false;
}
return true;
}
}
Update 4
I've figured out a workaround...
public InventoryResponse getInventory(#Context HttpServletRequest request, #HeaderParam(IDENTITY_URL) String identityURL, #HeaderParam(ACCESS_TOKEN) String accessToken) {
String username = (String) request.getAttribute("username");
user = inventoryService.getUserById(username);
List<HcCount> counts = inventoryService.getCountsForUserId(username);
HcUser newUser = new HcUser();
newUser.setHcCounts(counts);
inventoryResponse.setUser(newUser);
return inventoryResponse;
}

Objectify 4 - Fields are not persisted

Using Objectify 4, name and price fields are not persisted when I save a MenuItem object.
Only Key, WriteOps and ID/Name are persisted in the debugging datastore.
#Entity
public class MenuItem extends BaseEntity {
private String name;
private double price;
public MenuItem() {
}
public MenuItem(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
Where BaseEntity is:
public abstract class BaseEntity implements Dto {
private static final long serialVersionUID = 8400346403708831769L;
#Id
protected Long id;
protected BaseEntity() {
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
BaseEntity other = (BaseEntity) obj;
if (id == null) {
if (other.id != null) {
return false;
}
} else if (!id.equals(other.id)) {
return false;
}
return true;
}
public Long getId() {
return id;
}
public void setId(#Nullable Long id) {
this.id = id;
}
public boolean isSaved() {
return (id != null);
}
}
and Dto is:
public interface Dto extends Serializable {
}
Any ideas? Thanks!
As stated on the Objectify mailing list, it may just be your viewing of the datastore that is missing this information.
Can you show some test code to save this data then retrieve it and print out the results rather than using the datastore viewer? I'd expect:
MenuItem toSave = new MenuItem("test", 6.3);
toSave.setId(1);
ofy().save().entity(toSave).now();
ofy().clear(); //Make sure we're not just looking at the current session.
MenuItem loaded = ofy().load().type(MenuItem.class).id(1).get();
assertEquals(loaded.getName(), "test");
assertEquals(loaded.getPrice(), 6.3);

Categories