Here is the code I am using:
Database:
CREATE TABLE IF NOT EXISTS `btech_faculty_assigned` (
`subject_id` varchar(8) NOT NULL,
`year` varchar(4) NOT NULL,
`section` varchar(1) NOT NULL,
`branch` varchar(10) NOT NULL,
`semister` varchar(1) NOT NULL,
`FID` varchar(10) NOT NULL,
`islab` varchar(1) NOT NULL,
PRIMARY KEY (`subject_id`,`year`,`section`,`branch`,`semister`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
hbm file:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.att_marks.students.BtechFacultyAssigned" table="btech_faculty_assigned">
<composite-id>
<key-property name="subjectID" column="subject_id"/>
<key-property name="year" column="year"/>
<key-property name="section" column="section"/>
<key-property name="branch" column="branch"/>
<key-property name="semister" column="semister"/>
</composite-id>
<property name="FID" column="FID"></property>
<property name="islab" column="islab"></property>
</class>
</hibernate-mapping>
POJO file:
package com.att_marks.students;
public class BtechFacultyAssigned {
private String subjectID;
public String getSubjectID() {
return subjectID;
}
public void setSubjectID(String subjectID) {
this.subjectID = subjectID;
}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
public String getSeciton() {
return section;
}
public void setSeciton(String section) {
this.section = section;
}
public String getFID() {
return FID;
}
public void setFID(String fID) {
FID = fID;
}
public String getSemister() {
return semister;
}
public void setSemister(String semister) {
this.semister = semister;
}
public String getBranch() {
return branch;
}
public void setBranch(String branch) {
this.branch = branch;
}
public String getIslab() {
return islab;
}
public void setIslab(String islab) {
this.islab = islab;
}
private String year;
private String section;
private String FID;
private String semister;
private String branch;
private String islab;
}
The entire project works fine as long as this hbm file is not included in the configuration file. The moment this file is included in the configuration file, the sessionFactory.createQuery(query) file throws null pointer exception.
The Hibernate doc said:
A table with a composite key can be
mapped with multiple properties of the
class as identifier properties. The
element accepts
property mappings and
mappings as child
elements.
The persistent class must override
equals() and hashCode() to implement
composite identifier equality. It must
also implement Serializable.
Even if this is maybe not the cause of your problem (but the behavior looks like), you have to follow this requirements and add equals, hashcode and serilizable.
Related
I have app which is storing parsed urls inside MySQL db and populating parsed sentences, then parsed Words etc. using cascade (so I just save url, db insert rest automatically).
In the ProcessedUrl POJO I have fields:
Long id
String url
Date date
Set<Sentence> sentences
For now PK is id which is generated in native way. I want to achieve something like that - when user enter some url which is already parsed and stored into db, it won't be parsed again/duplicated.
What is suitable way of achieving this using hbm.xml mapping?
EDIT:
ProcessedUrl POJO:
public class ProcessedUrl {
private long id;
private String url;
private Date date;
private Set<Sentence> sentences;
public ProcessedUrl() {
}
public ProcessedUrl(String url, Date date) {
this.setUrl(url);
this.setDate(date);
}
public ProcessedUrl(String url, Date date, Set<Sentence> sentences) {
this.setUrl(url);
this.setDate(date);
this.setSentences(sentences);
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Set<Sentence> getSentences() {
return this.sentences;
}
public void setSentences(Set<Sentence> sentences) {
this.sentences = sentences;
}
#Override
public boolean equals(Object obj) {
if(this == obj) return true;
if(!(obj instanceof ProcessedUrl)) return false;
ProcessedUrl that = (ProcessedUrl) obj;
EqualsBuilder eb = new EqualsBuilder();
eb.append(this.getUrl(), that.getUrl());
return eb.isEquals();
}
#Override
public int hashCode() {
HashCodeBuilder hcb = new HashCodeBuilder();
hcb.append(url);
return hcb.toHashCode();
}
}
ProcessedUrl.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="model">
<class name="ProcessedUrl">
<id name="id">
<column name="url_id" />
<generator class="native"/>
</id>
<property name="url" type="text"/>
<property name="date" type="java.util.Date" />
<set name="sentences" cascade="all" >
<key column="PROCESSED_URL_ID" />
<one-to-many class="model.Sentence" />
</set>
</class>
</hibernate-mapping>
When user enters some url, which is already parsed and stored into db,
it won't be parsed again/duplicated. What is suitable way of achieving
this using hbm.xml mapping ?
You can't do this with simple hbm mappings because the previously parsed URL is already stored in the database and you need to validate that the latest received URL value already exists in the database.
So, to achieve this, you need to follow the below steps:
(1) Get the URL from App (DO NOT PARSE HERE)
(2) Check the URL already exists in database
(3) If URL does NOT exist, PARSE THE URL NOW and save to database
(4) If URL already exists, log an warning/error or ignore the request
I am trying to use Hibernate but when I execute a query I receive a list of my entity where all the attributes are NULL. The thing is that when i use the jdbc directly I am able to retrieve the values from my Db.
I read similar articles about NULL values but couldn't figure out what s wrong in my case.
Below you see:
1) My entity: Eshop
public class Eshop implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
public Eshop() {}
public Eshop(int eshopId, String code, String name, String lastModified) {
this.eshopId = eshopId;
this.code = code;
this.name = name;
this.lastModified = lastModified;
}
public int eshopId;
public String code;
public String name;
public String lastModified;
public int getEshopId() {
return eshopId;
}
public void setEshopId(int eshopId) {
eshopId = eshopId;
}
public String getCode() {
return code;
}
public void setCode(String code) {
code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
name = name;
}
public String getLastModified() {
return lastModified;
}
public void setLastModified(String lastModified) {
lastModified = lastModified;
}
2) The Hibernate Mapping
<hibernate-mapping>
<class name="dataModel.Eshop" table="Eshop">
<meta attribute="class-description">
This class contains the Eshop details.
</meta>
<id name="eshopId" type="int" column="EshopId">
<generator class="native"/>
</id>
<property name="code" column="Code" type="string"/>
<property name="name" column="Name" type="string"/>
<property name="lastModified" column="LastModified" type="string"/>
</class>
</hibernate-mapping>
And this is how I run the query:
Configuration config = new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory();
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Query hibernateQuery = session.createQuery("from Eshop");
List<Eshop> Eshops = hibernateQuery.list();
So when I run a query i receive the exact number of Eshops which are in my Db but all their attributes values are null!!
An ideas?? Thank you
All your setters are wrong:
public void setEshopId(int eshopId) {
eshopId = eshopId;
}
This is a noop. It should be
public void setEshopId(int eshopId) {
this.eshopId = eshopId;
}
Try to add hibernate.cfg.xml like this:
Configuration config = new Configuration().configure("hibernate.cfg.xml");
I am writing an order.hbm.xml file for my POJO class as below using Hibernate 3.0
import java.util.Set;
public class OrderDAO
{
private EmbeddedCustDAO embedCustID;
private Set<String> custOrderSet;
private String totalAmount;
public EmbeddedCustDAO getEmbedCustID()
{
return embedCustID;
}
public void setEmbedCustID(EmbeddedCustDAO embedCustID)
{
this.embedCustID = embedCustID;
}
public Set<String> getCustOrderSet()
{
return custOrderSet;
}
public void setCustOrderSet(Set<String> custOrderSet)
{
this.custOrderSet = custOrderSet;
}
public String getTotalAmount()
{
return totalAmount;
}
public void setTotalAmount(String totalAmount)
{
this.totalAmount = totalAmount;
}
}
The Embedded/ Composite ID class is,
public class EmbeddedCustDAO
{
private String customerName;
private String custAddress;
public String getCustomerName()
{
return customerName;
}
public void setCustomerName(String customerName)
{
this.customerName = customerName;
}
public String getCustAddress()
{
return custAddress;
}
public void setCustAddress(String custAddress)
{
this.custAddress = custAddress;
}
}
The order.hbm.xml file that I have written is,
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.harish.dao.OrderDAO"
table="order_table">
<composite-id name="embedCustId"
class="org.harish.dao.EmbeddedCustDAO">
<key-property name="customerName"/>
<key-property name="custAddress" />
</composite-id>
<set name="custOrderSet">
<key column="??" />
<element type="string" column="??"/>
</set>
<property name="totalAmount" />
</class>
</hibernate-mapping>
I am not sure how to declare the set in the order.hbm.xml above.
I went through the Hibernate 3.0 Reference. It mentions the key column in the Set to be column name of the Primary Key defined in the .hbm.xml. But, with a composite ID what would be the Column name?
Is a one-to-many mapping required here for the Set?
I have this Oracle table:
SQL> Name Null? Type
----------------------------------------- -------- ----------------------------
JOB_ID NOT NULL VARCHAR2(13)
TYPE NOT NULL NUMBER
COMPONENT_DESCRIPTION NOT NULL VARCHAR2(255)
COMPONENT_ID VARCHAR2(13)
STATUS NOT NULL NUMBER(1)
REASON VARCHAR2(255)
NOTES VARCHAR2(255)
SQL>
There is no defined primary key but JOB_ID, TYPE and COMPONENT_DESCRIPTION combined are unique. I cannot make any changes to the database structure and the code I'm working will only ever read from the DB, it will never write to it.
I have made this Hibernate map file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"classpath://org/hibernate/hibernate-mapping-3.0.dtd">
<hibernate-mapping schema="ARCHIVE">
<class name="myclass.ArchiveJobHeaderComponents" table="JOB_HEADER_COMPONENTS">
<composite-id>
<key-property name="jobId" column="JOB_ID" type="java.lang.String" />
<key-property name="type" column="TYPE" type="java.lang.Number" />
<key-property name="componentDescription" column="COMPONENT_DESCRIPTION" type="java.lang.String" />
</composite-id>
<property name="componentId" column="COMPONENT_ID" type="java.lang.String" not-null="false" />
<property name="status" column="STATUS" type="java.lang.Number" />
<property name="reason" column="REASON" type="java.lang.String" not-null="false" />
<property name="notes" column="NOTES" type="java.lang.String" not-null="false" />
</class>
<query name="JobHeaderComponents.lookupJobHeaderComponents">
<![CDATA[from myclass.ArchiveJobHeaderComponents where
jobId = :jobId and
type = :type and
componentDescription = :componentDescription ]]>
</query>
<query name="JobHeaderComponents.listJobHeaderComponentsByComponentId">
<![CDATA[from myclass.ArchiveJobHeaderComponents where componentId = :id]]>
</query>
</hibernate-mapping>
This is the corresponding Java class file:
package myclass;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import java.io.Serializable;
import java.lang.Number;
import java.util.HashSet;
public class ArchiveJobHeaderComponents implements Serializable {
private String jobId;
private Number type;
private String componentDescription;
private String componentId;
private Number status;
private String reason;
private String notes;
public String getJobId() {
return jobId;
}
public void setJobId(String jobId) {
this.jobId = jobId;
}
public Number getType() {
return type;
}
public void setType(Number type) {
this.type = type;
}
public String getComponentDescription() {
return componentDescription;
}
public void setComponentDescription(String componentDescription) {
this.componentDescription = componentDescription;
}
public String getComponentId() {
return componentId;
}
public void setComponentId(String componentId) {
this.componentId = componentId;
}
public Number getStatus() {
return status;
}
public void setStatus(Number status) {
this.status = status;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public String getNotes() {
return notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
public int hashCode() {
return new HashCodeBuilder().
append(getJobId()).
append(getType()).
append(getComponentDescription()).
append(getComponentId()).
append(getStatus()).
append(getReason()).
append(getNotes()).toHashCode();
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ArchiveJobHeaderComponents)) {
return false;
}
ArchiveJobHeaderComponents that = (ArchiveJobHeaderComponents) o;
return new EqualsBuilder().append(this.getJobId(), that.getJobId()).
append(this.getType(), that.getType()).
append(this.getComponentDescription(), that.getComponentDescription()).
append(this.getComponentId(), that.getComponentId()).
append(this.getStatus(), that.getStatus()).
append(this.getReason(), that.getReason()).
append(this.getNotes(), that.getNotes()).isEquals();
}
public String toString() {
return new ToStringBuilder(this).
append("jobId", getJobId()).
append("type", getType()).
append("componentDescription", getComponentDescription()).
append("componentId", getComponentId()).
append("status", getStatus()).
append("reason", getReason()).
append("notes", getNotes()).toString();
}
}
Whenever I get data back from a query, I get 'Could not deserialize' followed by an 'EOFException' error.
I've checked:
- There are no variables in the Java class of type serialize
- The Java class is implementing Serializable
I don't want to split the three columns (JOB_ID, TYPE and COMPONENT_DESCRIPTION) into a separate 'Id' class as I'm having conceptual problems with how the data is accessed. (I realize this is not recommended but is supported).
Can anyone point out what I've done wrong with how I've implemented this?
Thanks
EDIT:
I've changed the hbm.xml to not have a composite key, just an id on JOB_ID with no improvement.
I've added not-null="false" to the columns that can be empty, also no improvement.
Actually, having a look over the code and the Hibernate mapping file, I believe that the problem is that you are trying to map columns TYPE and STATUS to a Number. Number is an abstract class, so cannot be instantiated directly.
As both TYPE and STATUS are NOT NULL, I'd use primitive Java types to store their values, eg:
public class ArchiveJobHeaderComponents implements Serializable {
private String jobId;
private int type; // int should give you a large enough range - but change to long if required
private String componentDescription;
private String componentId;
private boolean status; // status appears to be a boolean (NUMBER(1))
private String reason;
private String notes;
// remainder omitted
}
Also, please remember to update the Hibernate mapping file to reflect the above!!
In case anyone else is working on a legacy Hibernate (3.0) app, something else that causes this error is running the app with Java 8 and OJDBC 1.4. Upgrading to OJDBC 6 resolved it.
I have a table named refund_rule in mysql(version 5.5). Here is it's definition:
CREATE TABLE `refund_rule` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`PERCENTAGE` char(0) DEFAULT NULL COMMENT 'BOOLEAN shortcut.NULL<=>false,EMPTY<=>true',
`DEDUCTION_AMOUNT` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`ID`)
);
The corresponding class in Hibernate(version 3.2) is named RefundRule. The HBM file looks like this:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernatesample.dao.RefundRule" table="refund_rule" catalog="back_end_proc">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="identity" />
</id>
<property name="percentage" type="string">
<column name="PERCENTAGE" length="0">
<comment>BOOLEAN shortcut.NULL<=>false,EMPTY<=>true</comment>
</column>
</property>
<property name="deductionAmount" type="java.lang.Integer">
<column name="DEDUCTION_AMOUNT" />
</property>
</class>
</hibernate-mapping>
The class generated by the wizard in NetBeans(version 7.0) was this:
public class RefundRule implements java.io.Serializable {
private Integer id;
private String percentage;
private Integer deductionAmount;
public CancellationRule() {
}
public CancellationRule(String percentage, Integer deductionAmount) {
this.percentage = percentage;
this.deductionAmount = deductionAmount;
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getPercentage() {
return this.percentage;
}
public void setPercentage(String percentage) {
this.percentage = percentage;
}
public Integer getDeductionAmount() {
return this.deductionAmount;
}
public void setDeductionAmount(Integer deductionAmount) {
this.deductionAmount = deductionAmount;
}
}
I added 2 more methods in it setPercentage(boolean) & isPercentage(), and changed the method setPercentage(String) , so that i can use that String object as boolean in my Java(version 1.6) program.
public class RefundRule implements java.io.Serializable {
.
.
.
public String getPercentage() {
return this.percentage;
}
public void setPercentage(String percentage) {
this.percentage = percentage==null?null:"";
}
.
.
.
public void setPercentage(boolean percentage){
setPercentage(percentage?"":null);
}
public boolean isPercentage(){
return percentage!=null;
}
}
My Question is:
Is there any way that I can keep only two methods: setPercentage(boolean) and isPercentage() , and map the boolean percentage variable to PERCENTAGE CHAR(0) variable in mysql.
===================================================================
EDIT added on 2013-11-23
Following the answer by #GreyBeardedGeek , I made following changes in code:
(Changes in brief)
Added Class CharToBoolUserType
Changed the type-attribute of hbm-element: percentage in RefundRule.hbm.xml
(Code related to above mentioned changes)
The class CharToBoolUserType:
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
public class CharToBoolUserType implements UserType {
private static final int[] SQL_TYPES = {Types.CHAR};
#Override
public Object assemble(Serializable serializable, Object object) throws HibernateException {
return serializable;
}
#Override
public Object deepCopy(Object object) throws HibernateException {
return object;
}
#Override
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}
#Override
public boolean equals(Object x, Object y) throws HibernateException {
if (x == y) {
return true;
} else if (x == null || y == null) {
return false;
} else {
return x.equals(y);
}
}
#Override
public boolean isMutable() {
return false;
}
#Override
public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws HibernateException, SQLException {
return resultSet.getObject(names[0]) != null;
}
#Override
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index) throws HibernateException, SQLException {
preparedStatement.setObject(index, ((Boolean) value).booleanValue() ? "" : null);
}
#Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}
#Override
public Class returnedClass() {
return boolean.class;
}
#Override
public int[] sqlTypes() {
return SQL_TYPES;
}
#Override
public int hashCode(Object object) throws HibernateException {
if (object == null) {
return 0;
}
// is `object` a String ? Or boolean?
return 1;
}
}
The file RefundRule.hbm.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernatesample.dao.RefundRule" table="refund_rule" catalog="back_end_proc">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="identity" />
</id>
<property name="percentage" type="hibernatesample.dao.CharToBoolUserType">
<column name="PERCENTAGE" length="0">
<comment>BOOLEAN shortcut.NULL<=>false,EMPTY<=>true</comment>
</column>
</property>
<property name="deductionAmount" type="java.lang.Integer">
<column name="DEDUCTION_AMOUNT" />
</property>
</class>
</hibernate-mapping>
Since I want the code of the class CharToBoolUserType to be complete in all sense, I have following questions:
1. What is the class of object in hashCode(Object object), Boolean or String? Who calls this method?
2. What the method public Object replace(Object original, Object target, Object owner) supposed to do? replace original with target and set/put it in owner. In this case: is original of String type, target of Boolean type, and owner of RefundRule type ?
Any suggestion(s) to improve this code is welcome.
=================================================
Just for reference, the class RefundRule is like this now:
public class RefundRule implements java.io.Serializable {
private Integer id;
private boolean percentage;
private Integer deductionAmount;
public RefundRule() {
}
public RefundRule(boolean percentage, Integer deductionAmount) {
this.percentage = percentage;
this.deductionAmount = deductionAmount;
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getDeductionAmount() {
return this.deductionAmount;
}
public void setDeductionAmount(Integer deductionAmount) {
this.deductionAmount = deductionAmount;
}
public void setPercentage(boolean percentage){
this.percentage=percentage;
}
public boolean isPercentage(){
return percentage;
}
}
I believe that you are looking for Hibernate's UserType, which allows you to provide a custom type mapping.
See, for example, http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/types.html#types-custom