I have a problem with Hibernate 4.3.0Final that I have been unable to solve. It is puzzling because I am running similar code in several other places which is working fine. The below code is throwing a java.lang.NullPointerException. It is running in a web service in using a NetBeans setup using Glassfish and JavaDB.
The exception is thrown after item.setRoomId(-1);:
characterId, characterFirstName, roomId, k, variables are being passed in from above; I have verified via debugging that they all have values with valid datatypes; also a valid record is in the Items table.
Query itemsQuery = em.createNamedQuery("Items.findByRoomIdByName");
itemsQuery.setParameter("roomId", roomId);
itemsQuery.setParameter("name", itemName);
Items item = null;
if (itemsQuery.getResultList().isEmpty()) {
throw new UnableToIdentifyException("Item does not exist! You cannot get an item that does not exist. Did you already pick it up?");
}
else {
item = (Items) itemsQuery.getSingleResult();
Boolean isStuck = item.getIsUnmovable();
if (isStuck) {
//Item stuck
notifyItemGetViewers(characterId, characterFirstName, roomId, itemName, isStuck);
}
else {
//Pick up item
try {
item.setRoomId(-1);
item.setCharacterId(characterId);
item.setStoreId(-1);
}
catch (Exception e) {
logger.severe("Wrapped Exection Caught: Exception: " + e.toString() + " Error Message: " + e.getMessage());
}
em.persist(item);
em.flush();
notifyItemGetViewers(characterId, characterFirstName, roomId, itemName, isStuck);
}
}
Entity class (Items.java)
package org.tav.mit;
import java.beans.*;
import java.io.Serializable;
import javax.persistence.*;
#Entity
#Table(name = "mit_items")
#NamedQueries({
#NamedQuery(name="Items.findByItemId",
query="SELECT i FROM Items i WHERE i.itemId = :itemId"),
#NamedQuery(name="Items.findByRoomIdByName",
query="SELECT i FROM Items i WHERE i.roomId = :roomId AND i.name = :name"),
#NamedQuery(name="Items.findByRoomId",
query="SELECT i FROM Items i WHERE i.roomId = :roomId"),
#NamedQuery(name="Items.findByCharacterId",
query="SELECT i FROM Items i WHERE i.characterId = :characterId"),
#NamedQuery(name="Items.findByStoreId",
query="SELECT i FROM Items i WHERE i.storeId = :storeId"),
#NamedQuery(name="Items.findByName",
query="SELECT i FROM Items i WHERE i.name = :name")
})
public class Items implements Serializable {
public static final String PROP_ITEMID = "itemIdProperty";
public static final String PROP_ROOMID = "roomIdProperty";
public static final String PROP_CHARACTERID = "characterIdProperty";
public static final String PROP_STOREID = "storeIdProperty";
public static final String PROP_NAME = "nameProperty";
public static final String PROP_DESCRIPTION = "descriptionProperty";
public static final String PROP_TYPE = "typeProperty";
public static final String PROP_WORTH = "worthProperty";
public static final String PROP_BODYLOCATION = "bodyLocationProperty";
public static final String PROP_ISUNMOVABLE = "isUnmovableProperty";
public static final String PROP_ACBONUS = "acBonusProperty";
public static final String PROP_USETIMEDELAY = "useTimeDelayProperty";
public static final String PROP_DAMAGEDICE = "damageDiceProperty";
public static final String PROP_DAMAGEDICESIDES = "damageDiceSidesProperty";
public static final String PROP_DAMAGETYPE = "damageTypeProperty";
public static final String PROP_LIGHTPROVIDED = "lightProvidedProperty";
#Id
#GeneratedValue
private Integer itemId;
#Column()
private Integer roomId = -1;
#Column()
private Integer characterId = -1;
#Column()
private Integer storeId = -1;
#Column(length = 128, nullable = false)
private String name;
#Column(length = 2048, nullable = true)
private String description;
#Column()
private Integer type = -1;
#Column()
private Double worth = 0.0;
#Column()
private Integer bodyLocation = -1;
#Column(nullable = false)
private Boolean isUnmovable = false;
#Column()
private Integer acBonus = -1;
#Column()
private Integer useTimeDelay = -1;
#Column()
private Integer damageDice = -1;
#Column()
private Integer damageDiceSides = -1;
#Column()
private Integer damageType = -1;
#Column(nullable = false)
private Boolean lightProvided = false;
#Column(length = 2048)
private PropertyChangeSupport propertySupport;
public Items()
{
propertySupport = new PropertyChangeSupport(this);
}
public int getItemId() {
return itemId;
}
public void setItemId(Integer itemId) {
Integer oldValue = this.itemId;
this.itemId = itemId;
propertySupport.firePropertyChange(PROP_ITEMID, oldValue, itemId);
}
public int getRoomId() {
return roomId;
}
public void setRoomId(Integer roomId) {
Integer oldValue = this.roomId;
this.roomId = roomId;
propertySupport.firePropertyChange(PROP_ROOMID, oldValue, roomId);
}
public int getCharacterId() {
return characterId;
}
public void setCharacterId(Integer characterId) {
Integer oldValue = this.characterId;
this.characterId = characterId;
propertySupport.firePropertyChange(PROP_CHARACTERID, oldValue, characterId);
}
public int getStoreId() {
return storeId;
}
public void setStoreId(Integer storeId) {
Integer oldValue = this.storeId;
this.storeId = storeId;
propertySupport.firePropertyChange(PROP_STOREID, oldValue, storeId);
}
public String getName() {
return name;
}
public void setName(String name) {
String oldValue = this.name;
this.name = name;
propertySupport.firePropertyChange(PROP_NAME, oldValue, name);
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
String oldValue = this.description;
this.description = description;
propertySupport.firePropertyChange(PROP_DESCRIPTION, oldValue, description);
}
public int getType() {
return type;
}
public void setType(Integer type) {
Integer oldValue = this.type;
this.type = type;
propertySupport.firePropertyChange(PROP_TYPE, oldValue, type);
}
public double getWorth() {
return worth;
}
public void setWorth(double worth) {
double oldValue = this.worth;
this.worth = worth;
propertySupport.firePropertyChange(PROP_WORTH, oldValue, worth);
}
public int getBodyLocation() {
return bodyLocation;
}
public void setBodyLocation(Integer bodyLocation) {
Integer oldValue = this.bodyLocation;
this.bodyLocation = bodyLocation;
propertySupport.firePropertyChange(PROP_BODYLOCATION, oldValue, bodyLocation);
}
public boolean getIsUnmovable() {
return isUnmovable;
}
public void setIsUnmovable(boolean isUnmovable) {
boolean oldValue = this.isUnmovable;
this.isUnmovable = isUnmovable;
propertySupport.firePropertyChange(PROP_ISUNMOVABLE, oldValue, isUnmovable);
}
public int getAcBonus() {
return acBonus;
}
public void setAcBonus(Integer acBonus) {
Integer oldValue = this.acBonus;
this.acBonus = acBonus;
propertySupport.firePropertyChange(PROP_ACBONUS, oldValue, acBonus);
}
public int getUseTimeDelay() {
return useTimeDelay;
}
public void setUseTimeDelay(Integer useTimeDelay) {
Integer oldValue = this.useTimeDelay;
this.useTimeDelay = useTimeDelay;
propertySupport.firePropertyChange(PROP_USETIMEDELAY, oldValue, useTimeDelay);
}
public int getDamageDice() {
return damageDice;
}
public void setDamageDice(Integer damageDice) {
Integer oldValue = this.damageDice;
this.damageDice = damageDice;
propertySupport.firePropertyChange(PROP_DAMAGEDICE, oldValue, damageDice);
}
public int getDamageDiceSides() {
return damageDiceSides;
}
public void setDamageDiceSides(Integer damageDiceSides) {
Integer oldValue = this.damageDiceSides;
this.damageDiceSides = damageDiceSides;
propertySupport.firePropertyChange(PROP_DAMAGEDICESIDES, oldValue, damageDiceSides);
}
public int getDamageType() {
return damageType;
}
public void setDamageType(Integer damageType) {
Integer oldValue = this.damageType;
this.damageType = damageType;
propertySupport.firePropertyChange(PROP_DAMAGETYPE, oldValue, damageType);
}
public boolean getLightProvided() {
return lightProvided;
}
public void setLightProvided(boolean lightProvided) {
boolean oldValue = this.lightProvided;
this.lightProvided = lightProvided;
propertySupport.firePropertyChange(PROP_LIGHTPROVIDED, oldValue, lightProvided);
}
#Override
public int hashCode() {
int hash = 0;
hash += (itemId != -1 ? itemId.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 Items)) {
return false;
}
Items other = (Items) object;
if ((this.itemId == -1 && other.itemId != -1) || (this.itemId != -1 &&
!((this.itemId) == (other.itemId)))) {
return false;
}
return true;
}
}
THE DATA THAT IS IN THE ITEMS TABLE:
INSERT INTO mit_items (roomid, characterid, storeid, name, description, type, worth, bodylocation, isunmovable, acbonus, useTimeDelay, damageDice, damageDiceSides, damageType, lightprovided) VALUES(1, -1, -1, 'sword', 'plain steel sword', -1, 0.0, -1, false, -1, -1, -1, -1, -1, false);
One interesting thing is that after the exception throws the database shows that the roomId has in fact been set to -1. However the other fields have not been updated. If I reorder the setFields(-1) methods the exception still trigger on the first method. Also, originally the try-catch block was not there. I had to add it in order to see the root cause exception because this method has the #Transactional annotation which wraps the exception in a general RollbackException that does not show the root cause exception.
Thanks, RC that fixed the problem. propertySupport was returning null. Not sure why, it normally has a Long number cast to a String in there. I ended up removing propertySupport from Items.java Entity class which fixed the problem.
I have feeling why it was failing in this case and not others is because I was manually inserting a record in the Items table for testing and I left the propertySupport field null. So apparently if you have propertySupport implemented you cannot update values in a record that has a null propertySupport field, which I guess would only occur if you inserted the data by a means other than the entity bean.
Thanks again RC! – Sam
Related
I have a REST endpoint as shown below.
#Path("/consumers")
#Produces("application/x.com.abc.pqr.audit.v2+json")
#Consumes("application/x.com.abc.pqr.audit.v2+json")
public interface ConsumerEndpoint {
#GET
#Path("paged")
Page<Module> getConsumersOfDependencyByPage(#BeanParam ConsumerQueryParams params);
}
As you can see above, I am using #BeanParam to map the query parameters passed from the front end side.
The ConsumerQueryParams class is shown below.
public class ConsumerQueryParams implements Serializable{
private static final long serialVersionUID = 6440255704974023223L;
#QueryParam("pageNum") #DefaultValue("1") private int pageNum;
#QueryParam("pageSize") #DefaultValue("25") private int pageSize;
#QueryParam("groupId") private String groupId;
#QueryParam("artifactId") private String artifactId;
#QueryParam("version") private String version;
#QueryParam("groupIdFilter") private String groupIdFilter;
#QueryParam("artifactIdFilter") private String artifactIdFilter;
#QueryParam("versionFilter") private String versionFilter;
public ConsumerQueryParams() {
}
private ConsumerQueryParams(Builder builder) {
this.pageNum = builder.pageNum;
this.pageSize = builder.pageSize;
this.groupId = builder.groupId;
this.artifactId = builder.artifactId;
this.version = builder.version;
this.groupIdFilter = builder.groupIdFilter;
this.artifactIdFilter = builder.artifactIdFilter;
this.versionFilter = builder.versionFilter;
}
public int getPageNum() {
return pageNum;
}
public int getPageSize() {
return pageSize;
}
public String getGroupId() {
return groupId;
}
public String getArtifactId() {
return artifactId;
}
public String getVersion() {
return version;
}
public String getGroupIdFilter() {
return groupIdFilter;
}
public String getArtifactIdFilter() {
return artifactIdFilter;
}
public String getVersionFilter() {
return versionFilter;
}
#Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if(!(obj instanceof ConsumerQueryParams))
return false;
ConsumerQueryParams other = (ConsumerQueryParams) obj;
return Objects.equals(pageNum, other.pageNum) &&
Objects.equals(pageSize, other.pageSize) &&
Objects.equals(groupId, other.groupId) &&
Objects.equals(artifactId, other.artifactId) &&
Objects.equals(version, other.version) &&
Objects.equals(groupIdFilter, other.groupIdFilter) &&
Objects.equals(artifactIdFilter, other.artifactIdFilter) &&
Objects.equals(versionFilter, other.versionFilter);
}
#Override
public int hashCode() {
return Objects.hash(pageNum, pageSize, groupId, artifactId, version, groupIdFilter, artifactIdFilter, versionFilter);
}
public static class Builder {
private int pageNum;
private int pageSize;
private String groupId;
private String artifactId;
private String version;
private String groupIdFilter;
private String artifactIdFilter;
private String versionFilter;
public Builder(int pageNum, int pageSize, String groupId, String artifactId) {
Preconditions.checkArgument(pageNum > 0, "pageNum must be greater than 0.");
Preconditions.checkArgument(pageSize > 0, "pageSize must be greater than 0.");
Preconditions.checkNotNull(groupId, "groupId is null");
Preconditions.checkNotNull(artifactId, "artifactId is null");
this.pageNum = pageNum;
this.pageSize = pageSize;
this.groupId = groupId;
this.artifactId = artifactId;
}
public Builder setVersion(String version) {
this.version = version;
return this;
}
public Builder setGroupIdFilter(String groupIdFilter) {
this.groupIdFilter = groupIdFilter;
return this;
}
public Builder setArtifactIdFilter(String artifactIdFilter) {
this.artifactIdFilter = artifactIdFilter;
return this;
}
public Builder setVersionFilter(String versionFilter) {
this.versionFilter = versionFilter;
return this;
}
public ConsumerQueryParams build() {
return new ConsumerQueryParams(this);
}
}
}
You can see that I am using the Builder pattern to set the variables.
I am using the below url to access the above specified endpoint.
http://localhost:8080/rest/api/consumers/paged?groupId=org.slf4j&artifactId=slf4j-api&groupIdFilter=sdlc
Everything works fine. I am able to get the data on Postman successfully.
Now I have a requirement where I need to rename the groupIdFilter, artifactIdFilter, versionFilter query params in ConsumerQueryParams class to consumerGroupIdFilter, consumerArtifactIdFilter and consumerVersionFilter respectively.
After changing the variable names in ConsumerQueryParams class, it looks like this:
public class ConsumerQueryParams implements Serializable{
private static final long serialVersionUID = 6440255704974023223L;
#QueryParam("pageNum") #DefaultValue("1") private int pageNum;
#QueryParam("pageSize") #DefaultValue("25") private int pageSize;
#QueryParam("groupId") private String groupId;
#QueryParam("artifactId") private String artifactId;
#QueryParam("version") private String version;
#QueryParam("groupIdFilter") private String consumerGroupIdFilter;
#QueryParam("artifactIdFilter") private String consumerArtifactIdFilter;
#QueryParam("versionFilter") private String consumerVersionFilter;
public ConsumerQueryParams() {
}
private ConsumerQueryParams(Builder builder) {
this.pageNum = builder.pageNum;
this.pageSize = builder.pageSize;
this.groupId = builder.groupId;
this.artifactId = builder.artifactId;
this.version = builder.version;
this.consumerGroupIdFilter = builder.consumerGroupIdFilter;
this.consumerArtifactIdFilter = builder.consumerArtifactIdFilter;
this.consumerVersionFilter = builder.consumerVersionFilter;
}
public int getPageNum() {
return pageNum;
}
public int getPageSize() {
return pageSize;
}
public String getGroupId() {
return groupId;
}
public String getArtifactId() {
return artifactId;
}
public String getVersion() {
return version;
}
public String getConsumerGroupIdFilter() {
return consumerGroupIdFilter;
}
public String getConsumerArtifactIdFilter() {
return consumerArtifactIdFilter;
}
public String getConsumerVersionFilter() {
return consumerVersionFilter;
}
#Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if(!(obj instanceof ConsumerQueryParams))
return false;
ConsumerQueryParams other = (ConsumerQueryParams) obj;
return Objects.equals(pageNum, other.pageNum) &&
Objects.equals(pageSize, other.pageSize) &&
Objects.equals(groupId, other.groupId) &&
Objects.equals(artifactId, other.artifactId) &&
Objects.equals(version, other.version) &&
Objects.equals(consumerGroupIdFilter, other.consumerGroupIdFilter) &&
Objects.equals(consumerArtifactIdFilter, other.consumerArtifactIdFilter) &&
Objects.equals(consumerVersionFilter, other.consumerVersionFilter);
}
#Override
public int hashCode() {
return Objects.hash(pageNum, pageSize, groupId, artifactId, version, consumerGroupIdFilter, consumerArtifactIdFilter, consumerVersionFilter);
}
public static class Builder {
private int pageNum;
private int pageSize;
private String groupId;
private String artifactId;
private String version;
private String consumerGroupIdFilter;
private String consumerArtifactIdFilter;
private String consumerVersionFilter;
public Builder(int pageNum, int pageSize, String groupId, String artifactId) {
Preconditions.checkArgument(pageNum > 0, "pageNum must be greater than 0.");
Preconditions.checkArgument(pageSize > 0, "pageSize must be greater than 0.");
Preconditions.checkNotNull(groupId, "groupId is null");
Preconditions.checkNotNull(artifactId, "artifactId is null");
this.pageNum = pageNum;
this.pageSize = pageSize;
this.groupId = groupId;
this.artifactId = artifactId;
}
public Builder setVersion(String version) {
this.version = version;
return this;
}
public Builder setConsumerGroupIdFilter(String consumerGroupIdFilter) {
this.consumerGroupIdFilter = consumerGroupIdFilter;
return this;
}
public Builder setConsumerArtifactIdFilter(String consumerArtifactIdFilter) {
this.consumerArtifactIdFilter = consumerArtifactIdFilter;
return this;
}
public Builder setConsumerVersionFilter(String consumerVersionFilter) {
this.consumerVersionFilter = consumerVersionFilter;
return this;
}
public ConsumerQueryParams build() {
return new ConsumerQueryParams(this);
}
}
}
Now I am trying to access the same endpoint with the url:
http://localhost:8080/rest/api/consumers/paged?groupId=org.slf4j&artifactId=slf4j-api&consumerGroupIdFilter=sdlc
But this is not working. The consumerGroupIdFilter query param in the url is not being mapped to the consumerGroupIdFilter variable of the ConsumerQueryParams object, whereas groupId and artifactId gets mapped.
I am not sure why this is happening. As far as I know, the ConsumerQueryParams class has the correct code. All that I did was to change the variable names and updated the getters and setters in the Builder class.
Can anyone help me here.
The problem is that the url has the new name and the annotation has the old one
#QueryParam("groupIdFilter")
consumerGroupIdFilter
public class AfpProcessSummaryDetail implements Serializable {
private String srNo;
private String fileName;
private String status;
private String location;
private String comments;
private Character convertStatus;
private AfpProcessDetail afpProcessDetail;
public AfpProcessSummaryDetail() {
}
public AfpProcessSummaryDetail(String srNo, String fileName, String status, String location, String comments,
AfpProcessDetail afpProcessDetail) {
this.srNo = srNo;
this.fileName = fileName;
this.status = status;
this.location = location;
this.comments = comments;
this.afpProcessDetail = afpProcessDetail;
}
#ManyToOne
#JoinColumn(name = "PROCESSDETAIL")
public AfpProcessDetail getAfpProcessDetail() {
return afpProcessDetail;
}
AfpProcessDetail
public class AfpProcessDetail implements Serializable {
private String processID;
private String processDate;
private Integer fileCount;
private Integer successCount;
private Integer failureCount;
private Character active;
private Set<AfpProcessSummaryDetail> processSummaryDetails = new HashSet<AfpProcessSummaryDetail>(0);
public AfpProcessDetail() {
}
public AfpProcessDetail(String processID, String processDate, Integer fileCount, Integer successCount,
Integer failureCount) {
this.processID = processID;
this.processDate = processDate;
this.fileCount = fileCount;
this.successCount = successCount;
this.failureCount = failureCount;
}
public AfpProcessDetail(String processID, String processDate, Integer fileCount, Integer successCount,
Integer failureCount, Set<AfpProcessSummaryDetail> processSummaryDetails) {
this.processID = processID;
this.processDate = processDate;
this.fileCount = fileCount;
this.successCount = successCount;
this.failureCount = failureCount;
this.processSummaryDetails = processSummaryDetails;
}
#Column(name = "FAILURECOUNT")
public Integer getFailureCount() {
return failureCount;
}
public void setFailureCount(Integer failureCount) {
this.failureCount = failureCount;
}
#Column(name = "FILECOUNT")
public Integer getFileCount() {
return fileCount;
}
public void setFileCount(Integer fileCount) {
this.fileCount = fileCount;
}
#Column(name = "PROCESSDATE")
public String getProcessDate() {
return processDate;
}
public void setProcessDate(String processDate) {
this.processDate = processDate;
}
#Id
#Column(name = "PROCESSID", unique = true, nullable = false)
public String getProcessID() {
return processID;
}
public void setProcessID(String processID) {
this.processID = processID;
}
#Column(name = "SUCESSCOUNT")
public Integer getSuccessCount() {
return successCount;
}
public void setSuccessCount(Integer successCount) {
this.successCount = successCount;
}
#JoinColumn(name="PROCESSDETAIL")
#OneToMany(cascade=CascadeType.ALL,fetch = FetchType.EAGER)
public Set<AfpProcessSummaryDetail> getProcessSummaryDetails() {
return processSummaryDetails;
}
public void setProcessSummaryDetails(Set<AfpProcessSummaryDetail> processSummaryDetails) {
this.processSummaryDetails = processSummaryDetails;
}
Code for updating
public String updateSummaryDetails(ViewFile viewFile, String codeID) {
if (viewFile != null && codeID != null) {
HibernateTemplate transactionTemplate = new HibernateTemplate(sessionFactory, true);
Object result = transactionTemplate.execute(new HibernateCallback<Object>() {
#Override
public Object doInHibernate(org.hibernate.Session session) throws HibernateException, SQLException {
AfpProcessSummaryDetail processSummary =null,newProcessSummary =null;
AfpProcessDetail processDetail = (AfpProcessDetail)session.get(AfpProcessDetail.class,codeID);
List<FileProperty> fileList = viewFile.getFileList();
Set<AfpProcessSummaryDetail> setProcessSummary=new HashSet<AfpProcessSummaryDetail>();
Set<AfpProcessSummaryDetail> modSetProcessSummary=new HashSet<AfpProcessSummaryDetail>();
setProcessSummary =processDetail.getProcessSummaryDetails();
Iterator<AfpProcessSummaryDetail> itrProcessSumm=setProcessSummary.iterator();
int srNo = 0;
while (itrProcessSumm.hasNext()){
processSummary =(AfpProcessSummaryDetail)itrProcessSumm.next();
for (FileProperty fileProperty : fileList) {
newProcessSummary =new AfpProcessSummaryDetail();
newProcessSummary.setSrNo(codeID + "" + srNo);
newProcessSummary.setFileName(fileProperty.getName());
newProcessSummary.setLocation(fileProperty.getPath());
newProcessSummary.setComments(fileProperty.getComment());
newProcessSummary.setStatus(fileProperty.getStatus());
newProcessSummary.setConvertStatus(fileProperty.getConvertStatus());
newProcessSummary.setAfpProcessDetail(processDetail);
modSetProcessSummary.add(newProcessSummary);
/*if (processSummary.getFileName().trim().equals(fileProperty.getName().trim())){
System.out.println("Element removed");
itrProcessSumm.remove();
modSetProcessSummary.add(newProcessSummary);
break;
}*/
srNo++;
}
}
// setProcessSummary.addAll(modSetProcessSummary);
processDetail.setProcessSummaryDetails(modSetProcessSummary);
processDetail.setFailureCount(viewFile.getExceptionNo());
processDetail.setSuccessCount(viewFile.getSuccessNo());
processDetail.setActive(viewFile.getActive());
transactionTemplate.flush();
session.merge(processDetail);
System.out.println("updated successfully");
return codeID;
}
});
Desired result
I want to perform a one to many update -AfpProcessSummaryDetail which is related to AfpProcessDetail via Set. When I try to replace the set values for update it tries to update the primary key to null. If I don't replace the updates don't take place. If I set cascade it gives error -a different object with the same identifier value was already associated with the session:
[com.aurionpro.convertor.dto.AfpProcessSummaryDetail#15a236ffc961];
nested exception is org.hibernate.NonUniqueObjectException: a
different object with the same identifier value was already associated
with the session.
Please suggest
We recently ran across a bug in our software due to a missing #Id annotation:
#Entity
#Table (name ="PATRONQRSPLANS")
//#IdClass(PatronPlan.class) <-- this was missing
public class Balance {
#Transient
private String kind;
#Transient
private String planName;
#Transient
private PlanCategory planCategory;
#Id
#Column(name="PATRONID")
private int patronId;
//#Id <--- and this was missing
#Column(name="PLANID")
private int planId;
#Column(name="BALANCE")
private int balance;
#Column(name="ENDDATE")
private Date expirationDate;
public Balance() {
this.kind = "balance";
}
public Balance(int balance, int planId, Date expirationDate) {
this.balance = balance;
this.planId = planId;
this.expirationDate = expirationDate;
this.kind = "balance";
}
public int getPatronId() {
return patronId;
}
public void setPatronId(int patronId) {
this.patronId = patronId;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
public int getPlanId() {
return planId;
}
public void setPlanId(int planId) {
this.planId = planId;
}
public String getPlanName() {
return planName;
}
public void setPlanName(String planName) {
this.planName = planName;
}
public String getKind() {
return kind;
}
public void setKind(String kind) {
this.kind = kind;
}
public Date getExpirationDate() {
return expirationDate;
}
public void setExpirationDate(Date expirationDate) {
this.expirationDate = expirationDate;
}
public PlanCategory getPlanCategory() {
return planCategory;
}
public void setPlanCategory(PlanCategory planCategory) {
this.planCategory = planCategory;
}
}
The problem is that the table has a primary key constraint on both planId and patronId, so I need a composite key. The query below (without the commented out annotations above), for a patron that has 2 different plans, will return 2 copies of the same plan instead of 2 different ones.
public List<Balance> getBalancesByPatronId(int patronId) {
CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Balance> query = builder.createQuery(Balance.class);
Root<Balance> s = query.from(Balance.class);
query.select(s);
query.where(builder.equal(s.get("patronId"), patronId));
return entityManager.createQuery(query).getResultList();
}
To remedy this, I added an #Id and #IdClass annotation as commented out above, as well as creating this class:
public class PatronPlan implements Serializable {
private static final long serialVersionUID = -3518083815234439123L;
#Id
#Column(name="PATRONID")
private int patronId;
#Id
#Column(name="PLANID")
private int planId;
public int getPatronId() {
return patronId;
}
public void setPatronId(int patronId) {
this.patronId = patronId;
}
public int getPlanId() {
return planId;
}
public void setPlanId(int planId) {
this.planId = planId;
}
#Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (!this.getClass().isAssignableFrom(obj.getClass())) return false;
PatronPlan other = (PatronPlan) obj;
return Objects.equals(patronId, other.getPatronId()) && Objects.equals(planId, other.getPlanId());
}
#Override
public int hashCode() {
return Objects.hash(patronId, planId);
}
}
But now I get a NullPointerException in my critera query on the statement
s.get("patronId"), because patronId is not showing up as a declaredAttribute, though it does seem to be showing up in the id information.
Is my composite key setup correct and how to I query for part of a composite key using the criteria api?
If it wasn't clear above, the goal is to be able to get all the Balance objects with a given patronId, even though patronId is only part of the composite key.
I am not certain if this is correct, but it seems to be working. Is this correct? My knowledge of hibernate is limited.
public List<Balance> getBalancesByPatronId(int patronId) {
CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Balance> query = builder.createQuery(Balance.class);
Metamodel metaModel = getEntityManager().getMetamodel();
SingularAttribute<Balance, Integer> patronIdAttr =
(SingularAttribute<Balance, Integer>) metaModel.entity(Balance.class)
.getIdClassAttributes().toArray()[0];
Root<Balance> s = query.from(Balance.class);
query.select(s);
query.where(builder.equal(s.get(patronIdAttr), patronId));
return entityManager.createQuery(query).getResultList();
}
I want to get my profile in class Tournee (profil_tournee) list based on my tours ("tournee"). However, I have an exception. Can anyone help me?
Exception in thread "AWT-EventQueue-0"
java.lang.IllegalArgumentException: Type specified for TypedQuery
[fr.galettedebroons.domain.Profil] is incompatible with query return
type [interface java.util.Collection]
Request:
List<List<Profil>> listProfil = Arrays.asList(manager_.createQuery("select t.profil_tournee "
+ "FROM Tournee t WHERE t.nom LIKE :tournee", Profil.class)
.setParameter("tournee", tournee)
.getResultList());
Model :
#Entity
public class Tournee {
private int id;
private String nom;
private boolean lundi = false;
private boolean mardi = false;
private boolean mercredi = false;
private boolean jeudi = false;
private boolean vendredi = false;
private boolean samedi = false;
private boolean dimanche = false;
private List<Profil> profil_tournee;
public Tournee(){}
public Tournee(String nom, boolean lundi, boolean mardi, boolean mercredi, boolean jeudi,
boolean vendredi, boolean samedi, boolean dimanche, List<Profil> profil_tournee) {
this.nom = nom;
this.lundi = lundi;
this.mardi = mardi;
this.mercredi = mercredi;
this.jeudi = jeudi;
this.vendredi = vendredi;
this.samedi = samedi;
this.dimanche = dimanche;
this.profil_tournee = profil_tournee;
}
public Tournee(String nom, boolean lundi, boolean mardi, boolean mercredi, boolean jeudi,
boolean vendredi, boolean samedi, boolean dimanche) {
this.nom = nom;
this.lundi = lundi;
this.mardi = mardi;
this.mercredi = mercredi;
this.jeudi = jeudi;
this.vendredi = vendredi;
this.samedi = samedi;
this.dimanche = dimanche;
}
#Id #GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
public void setId(int id_tournee) {
this.id = id_tournee;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public boolean isLundi() {
return lundi;
}
public void setLundi(boolean lundi) {
this.lundi = lundi;
}
public boolean isMardi() {
return mardi;
}
public void setMardi(boolean mardi) {
this.mardi = mardi;
}
public boolean isMercredi() {
return mercredi;
}
public void setMercredi(boolean mercredi) {
this.mercredi = mercredi;
}
public boolean isJeudi() {
return jeudi;
}
public void setJeudi(boolean jeudi) {
this.jeudi = jeudi;
}
public boolean isVendredi() {
return vendredi;
}
public void setVendredi(boolean vendredi) {
this.vendredi = vendredi;
}
public boolean isSamedi() {
return samedi;
}
public void setSamedi(boolean samedi) {
this.samedi = samedi;
}
public boolean isDimanche() {
return dimanche;
}
public void setDimanche(boolean dimanche) {
this.dimanche = dimanche;
}
#OneToMany(mappedBy="profil_tournee", cascade=CascadeType.PERSIST)
public List<Profil> getProfil_tournee() {
return profil_tournee;
}
public void setProfil_tournee(List<Profil> profil_tournee) {
this.profil_tournee = profil_tournee;
}
}
#Entity
public class Profil {
private String code_client;
private Client client_profil;
private Gamme gamme_profil;
private List<Livraison> livraison_profil;
private Boolean actif;
private Tournee profil_tournee;
private List<MargeLivraison> marge_profil;
private List<Prevision> prevision_profil;
public Profil(){}
public Profil(Gamme code_gamme, List<Livraison> livraison, Boolean actif) {
this.gamme_profil = code_gamme;
this.livraison_profil = livraison;
this.actif = actif;
}
#Id
public String getCode_client() {
return code_client;
}
public void setCode_client(String code_client) {
this.code_client = code_client;
}
public Boolean getActif() {
return actif;
}
public void setActif(Boolean actif) {
this.actif = actif;
}
#ManyToOne
public Gamme getGamme_profil() {
return gamme_profil;
}
public void setGamme_profil(Gamme gamme_profil) {
this.gamme_profil = gamme_profil;
}
#OneToMany(mappedBy="livraison_profil", cascade=CascadeType.PERSIST)
public List<Livraison> getLivraison_profil() {
return livraison_profil;
}
public void setLivraison_profil(List<Livraison> livraison_profil) {
this.livraison_profil = livraison_profil;
}
#ManyToOne
public Client getClient_profil() {
return client_profil;
}
public void setClient_profil(Client client) {
this.client_profil = client;
}
#ManyToOne
public Tournee getProfil_tournee() {
return profil_tournee;
}
public void setProfil_tournee(Tournee profil_tournee) {
this.profil_tournee = profil_tournee;
}
#OneToMany(mappedBy="marge_profil", cascade=CascadeType.PERSIST)
public List<MargeLivraison> getMarge_profil() {
return marge_profil;
}
public void setMarge_profil(List<MargeLivraison> marge_profil) {
this.marge_profil = marge_profil;
}
#OneToMany(mappedBy="prevision_profil", cascade=CascadeType.PERSIST)
public List<Prevision> getPrevision_profil() {
return prevision_profil;
}
public void setPrevision_profil(List<Prevision> prevision_profil) {
this.prevision_profil = prevision_profil;
}
Your expected result list will contain elements that are list of profiles, not profiles.
I would replace Profil.class by List.class for the Query creation :
List<List<Profil>> listProfil = Arrays.asList(manager_.createQuery("select t.profil_tournee "
+ "FROM Tournee t WHERE t.nom LIKE :tournee", List.class)
.setParameter("tournee", tournee)
.getResultList());
Your error gives you a hint that the returning type should be consistent with declared type when invoking EntityManager.createQuery(query, Type) method:
List<SomeType> em.createQuery("SELECT s FROM SomeType", SomeType.class);
However your real problem is that your query is illegal. In JPA collection-valued expressions cannot be part of SELECT clause. Please see another answer of mine https://stackoverflow.com/a/25890863/3796586.
The solution in your case would be to reverse the query like this:
List<Profil> result = em.createQuery("SELECT p FROM Profil p WHERE" +
"p.profil_tournee.norm LIKE :tournee", Profil.class)
.setParameter("tournee", tournee)
.getResultList());
I am creating the ArrayList of Object, to insert information I use different constructors in that class but I have one type variable that I update with every constructor call. here is what i am doing
public class eProperty {
public String type = null;
public int marks;
public int code;
public String category
public String student_name = null;
public String employee_name = null;
public String o_name = null;
public eProperty(String type, String student_name, int marks) {
this.marks = marks;
this.type = type;
this.student_name = student_marks;
}
public eProperty(String type, String employee_name, int makrs, String category) {
this.marks = marks;
this.type = type;
this.employee_name = employee_name;
this.category = category;
}
public eProperty(String type, int code, int makrs, String o_name) {
this.marks = marks;
this.type = type;
this.mnc = code;
this.o_name = o_name;
}
}
I populate arraylist like this,
ArrayList<eProperty> allData;
eProperty data;
if(type.equals("Student")) {
data = new eProperty(type, "John", 45)
allData.add(data)
}
if(type.equals("Employee")){
data = new eProperty(type, "Vicky", 86, "Developer")
allData.add(data)
} ... other cases also handled like this
Now I want to retrive highest marks for each type and I am stuck here, any help
Thanks
Using loop (sorry for that...) and Predicate from Apache Commons
public static int getHighestMarkByType(ArrayList<eProperty> allData, String type) {
Predicate predicate = new Predicate() {
public boolean evaluate(Object data) {
if ((eProperty) data).getType().equals(type)) {
return true;
} else {
return false;
}
}
};
ArrayList<eProperty> filteredData = (ArrayList<eProperty>) CollectionUtils.select(allData,predicate);
int maxMarks = 0;
for (eProperty data : filteredData) {
if (data.getMarks() > maxMark) {
maxMarks = data.getMark();
}
}
return maxMarks;
}