The issues is: "How do I tell Hibernate about namespaces?"
Background
I need to retrieve XML from a relational database. I've created a small prototype that retrieves an RSS feed from the database. I need some elements/attributes to be in a certain namespaces.
There does not seem to be a way to turn off some properties (like the id and version). Thus, I tried to put them in their own namespace (as is the standard for RSS feeds). I also have the need to have other elements that are in their own namespace.
Example hbm.xml mapping:
Code:
<hibernate-mapping package="com.qualcomm.news.model">
<class name="RssFeed"
node="rss">
<id name="id" type="integer" access="field"
node="newsService:id"
>
<generator class="native"/>
</id>
<version name="version" type="integer"
access="field"
node="newsService:version"/>
<property name="location"
type="string"
not-null="true"
access="field"
unique="true"
update="false"
node="@newsService:location"/>
...
...
...
<hibernate-mapping package="com.qualcomm.news.model">
<class name="Channel" node="channel">
<id name="id" type="integer" access="field"
node="newsService:id">
<generator class="native"/>
</id>
<version name="version" type="integer"
access="field"
node="newsService:version"/>
<property name="link"
type="string"
update="false"
unique="true"
not-null="true"
access="field"
/>
...
...
Notice in the node that I've added newsService namespace.
I get this error from Hibernate:
Code:
org.dom4j.IllegalAddException: No such namespace prefix: newsService is in scope on: org.dom4j.tree.DefaultElement@18e4327 [Element: <rss attributes: []/>] so cannot add element: newsService:id
at org.dom4j.tree.AbstractElement.addElement(AbstractElement.java:841)
at org.hibernate.property.Dom4jAccessor$ElementSetter.set(Dom4jAccessor.java:306)
at org.hibernate.tuple.AbstractTuplizer.setIdentifier(AbstractTuplizer.java:130)
at org.hibernate.tuple.AbstractTuplizer.instantiate(AbstractTuplizer.java:223)
at org.hibernate.persister.entity.BasicEntityPersister.instantiate(BasicEntityPersister.java:2959)
at org.hibernate.impl.SessionImpl.instantiate(SessionImpl.java:1049)
at org.hibernate.impl.SessionImpl.instantiate(SessionImpl.java:1041)
at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:933)
at org.hibernate.loader.Loader.getRow(Loader.java:855)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:305)
at org.hibernate.loader.Loader.doQuery(Loader.java:412)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:218)
at org.hibernate.loader.Loader.doList(Loader.java:1593)
at org.hibernate.loader.Loader.list(Loader.java:1577)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:395)
at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:271)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:844)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:74)
at ...
....
Here is the test that fails:
Code:
public void testStoreAndRetrieveFeedPrototype() {
/* Create a channel and save it to the database */
RssFeed feed = new RssFeed("http://www.arc-mind.com");
session.save(feed);
session.flush(); //Fluch so the the feed gets an id.
/* Test to see if we can read the feed that was just saved.*/
RssFeed feed2 = (RssFeed) session.get(RssFeed.class, feed.getId());
assertEquals("We can read and write a feed",feed.getLocation(), feed2.getLocation());
/* Test feed to channels */
/* Test to make sure the relationship is setup with the correct cascade option */
Channel channel = new Channel("http://www.arc-mind.com", "httpwwwarcmindcom");
feed.addChannel(channel);
RssFeed feed3 = (RssFeed) session.createQuery(
" from RssFeed feed " +
" left outer join fetch feed.channels " +
" where feed.id=?")
.setParameter(0, feed.getId()).uniqueResult();
assertEquals("The relationship of the feed to channel is working",
1,feed3.getChannels().size());
/* Test channels to items */
Item item = new Item("Hello", "Hello World");
channel.addItem(item);
Channel channel2 = (Channel) session.createQuery(
" from Channel channel " +
" left outer join fetch channel.items " +
" where channel.id=?")
.setParameter(0, channel.getId()).uniqueResult();
assertEquals("The relationship of the channel to item is working",
1,channel2.getItems().size());
session.flush();
Document doc = DocumentFactory.getInstance().createDocument();
Session dom4jSession = session.getSession(EntityMode.DOM4J);
Element root = doc.addElement("ROOT");
Query query = dom4jSession.createQuery("from RssFeed");
List list = query.list();
for (Iterator iter = list.iterator(); iter.hasNext();) {
Element element = (Element) iter.next();
System.out.println(element.toString());
root.add(element);
}
System.out.println(doc.asXML());
}
Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelpHibernate version: 3.0.5 Mapping documents:Code:
<?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 package="com.qualcomm.news.model">
<class name="Channel" node="channel">
<id name="id" type="integer" access="field"
node="newsService:id">
<generator class="native"/>
</id>
<version name="version" type="integer"
access="field"
node="newsService:version"/>
<property name="link"
type="string"
update="false"
unique="true"
not-null="true"
access="field"
/>
<property name="channelId"
type="string"
update="false"
unique="true"
not-null="true"
access="field"
/>
<property name="title"
type="string"/>
<property name="description"
type="string"/>
<property name="lastBuildDate"
type="timestamp"/>
<property name="pubDate"
type="timestamp"/>
<many-to-one name="feed" class="RssFeed" embed-xml="false"/>
<set name="items" cascade="all, delete-orphan" embed-xml="false">
<key column="FK_CHANNEL_ID_PARENT" not-null="true"/>
<one-to-many class="Item"/>
</set>
</class>
</hibernate-mapping>
<?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 package="com.qualcomm.news.model">
<class name="RssFeed"
node="rss">
<id name="id" type="integer" access="field"
node="newsService:id"
>
<generator class="native"/>
</id>
<version name="version" type="integer"
access="field"
node="newsService:version"/>
<property name="location"
type="string"
not-null="true"
access="field"
unique="true"
update="false"
node="@newsService:location"/>
<set name="channels"
cascade="all, delete-orphan"
embed-xml="true" inverse="false"
node=".">
<key column="FK_RSS_FEED_ID_PARENT" not-null="true"/>
<one-to-many class="Channel"/>
</set>
</class>
</hibernate-mapping>
<?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 package="com.qualcomm.news.model">
<class name="Item">
<id name="id" type="integer" access="field">
<generator class="native"/>
</id>
<version name="version" type="integer"
access="field"/>
<many-to-one name="channel" class="Channel" />
<property name="title"
type="string"
not-null="true"/>
<property name="post"
type="text"
not-null="true"
/>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close(): Code:
package com.qualcomm.news.dao;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import javax.sql.DataSource;
import junit.framework.TestCase;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.hibernate.EntityMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.springframework.core.io.ClassPathResource;
import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import com.qualcomm.news.model.Channel;
import com.qualcomm.news.model.Item;
import com.qualcomm.news.model.RssFeed;
public class HibernateRssFeedTest extends TestCase {
protected Logger logger;
private Transaction transaction;
private Session session;
{
logger = Logger.getLogger(this.getClass());
}
public HibernateRssFeedTest(String arg0) {
super(arg0);
}
protected void setUp() throws Exception {
logger.info("setUp");
LocalSessionFactoryBean localSessionFactoryBean = initSessionFactory();
SessionFactory factory = (SessionFactory) localSessionFactoryBean.getObject();
localSessionFactoryBean.createDatabaseSchema();
session =
SessionFactoryUtils.getSession(factory, true);
transaction = session.beginTransaction();
}
protected void tearDown() throws Exception {
//transaction.commit();
}
private LocalSessionFactoryBean initSessionFactory() throws IOException {
LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
DataSource dataSource = initDataSource();
localSessionFactoryBean.setDataSource(dataSource);
localSessionFactoryBean.setConfigLocation(new ClassPathResource("/hibernate.cfg.xml"));
localSessionFactoryBean.afterPropertiesSet();
return localSessionFactoryBean;
}
private DataSource initDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl("jdbc:hsqldb:file:/data/qualcomm/rssFeed");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
/*
* Test method for 'com.qualcomm.news.dao.HibernateRssFeedDAO.storeFeed(RssFeed)'
*/
public void testStoreAndRetrieveFeedPrototype() {
/* Create a channel and save it to the database */
RssFeed feed = new RssFeed("http://www.arc-mind.com");
session.save(feed);
session.flush(); //Fluch so the the feed gets an id.
/* Test to see if we can read the feed that was just saved.*/
RssFeed feed2 = (RssFeed) session.get(RssFeed.class, feed.getId());
assertEquals("We can read and write a feed",feed.getLocation(), feed2.getLocation());
/* Test feed to channels */
/* Test to make sure the relationship is setup with the correct cascade option */
Channel channel = new Channel("http://www.arc-mind.com", "httpwwwarcmindcom");
feed.addChannel(channel);
RssFeed feed3 = (RssFeed) session.createQuery(
" from RssFeed feed " +
" left outer join fetch feed.channels " +
" where feed.id=?")
.setParameter(0, feed.getId()).uniqueResult();
assertEquals("The relationship of the feed to channel is working",
1,feed3.getChannels().size());
/* Test channels to items */
Item item = new Item("Hello", "Hello World");
channel.addItem(item);
Channel channel2 = (Channel) session.createQuery(
" from Channel channel " +
" left outer join fetch channel.items " +
" where channel.id=?")
.setParameter(0, channel.getId()).uniqueResult();
assertEquals("The relationship of the channel to item is working",
1,channel2.getItems().size());
session.flush();
Document doc = DocumentFactory.getInstance().createDocument();
Session dom4jSession = session.getSession(EntityMode.DOM4J);
Element root = doc.addElement("ROOT");
Query query = dom4jSession.createQuery("from RssFeed");
List list = query.list();
for (Iterator iter = list.iterator(); iter.hasNext();) {
Element element = (Element) iter.next();
System.out.println(element.toString());
root.add(element);
}
System.out.println(doc.asXML());
}
public static void main(String[] args) {
junit.textui.TestRunner.run(HibernateRssFeedTest.class);
}
}
Full stack trace of any exception that occurs: org.dom4j.IllegalAddException: No such namespace prefix: newsService is in scope on: org.dom4j.tree.DefaultElement@18e4327 [Element: <rss attributes: []/>] so cannot add element: newsService:id
at org.dom4j.tree.AbstractElement.addElement(AbstractElement.java:841)
at org.hibernate.property.Dom4jAccessor$ElementSetter.set(Dom4jAccessor.java:306)
at org.hibernate.tuple.AbstractTuplizer.setIdentifier(AbstractTuplizer.java:130)
at org.hibernate.tuple.AbstractTuplizer.instantiate(AbstractTuplizer.java:223)
at org.hibernate.persister.entity.BasicEntityPersister.instantiate(BasicEntityPersister.java:2959)
at org.hibernate.impl.SessionImpl.instantiate(SessionImpl.java:1049)
at org.hibernate.impl.SessionImpl.instantiate(SessionImpl.java:1041)
at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:933)
at org.hibernate.loader.Loader.getRow(Loader.java:855)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:305)
at org.hibernate.loader.Loader.doQuery(Loader.java:412)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:218)
at org.hibernate.loader.Loader.doList(Loader.java:1593)
at org.hibernate.loader.Loader.list(Loader.java:1577)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:395)
at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:271)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:844)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:74)
at com.qualcomm.news.dao.HibernateRssFeedTest.testStoreFeed(HibernateRssFeedTest.java:136)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
[/code]
Name and version of the database you are using: Currently for prototype HSQL.
Production will be Oracle 10G release 2.
The generated SQL (show_sql=true): Hibernate: select rssfeed0_.id as id, rssfeed0_.version as version0_, rssfeed0_.location as location0_ from RssFeed rssfeed0_
Debug level Hibernate log excerpt:Code:
0 [main] INFO org.hibernate.cfg.Environment - Hibernate 3.0.5
0 [main] INFO org.hibernate.cfg.Environment - hibernate.properties not found
0 [main] INFO org.hibernate.cfg.Environment - using CGLIB reflection optimizer
0 [main] INFO org.hibernate.cfg.Environment - using JDK 1.4 java.sql.Timestamp handling
78 [main] INFO org.hibernate.cfg.Configuration - configuring from url: file:/D:/workspaces/qualcomm2/news_service/WebRoot/WEB-INF/classes/hibernate.cfg.xml
172 [main] INFO org.hibernate.cfg.Configuration - Mapping resource: com/qualcomm/news/model/RssFeed.hbm.xml
281 [main] INFO org.hibernate.cfg.HbmBinder - Mapping class: com.qualcomm.news.model.RssFeed -> RssFeed
313 [main] INFO org.hibernate.cfg.Configuration - Mapping resource: com/qualcomm/news/model/Channel.hbm.xml
344 [main] INFO org.hibernate.cfg.HbmBinder - Mapping class: com.qualcomm.news.model.Channel -> Channel
406 [main] INFO org.hibernate.cfg.Configuration - Mapping resource: com/qualcomm/news/model/Item.hbm.xml
438 [main] INFO org.hibernate.cfg.HbmBinder - Mapping class: com.qualcomm.news.model.Item -> Item
438 [main] INFO org.hibernate.cfg.Configuration - Configured SessionFactory: null
438 [main] INFO org.hibernate.cfg.Configuration - processing extends queue
438 [main] INFO org.hibernate.cfg.Configuration - processing collection mappings
438 [main] INFO org.hibernate.cfg.HbmBinder - Mapping collection: com.qualcomm.news.model.RssFeed.channels -> Channel
438 [main] INFO org.hibernate.cfg.HbmBinder - Mapping collection: com.qualcomm.news.model.Channel.items -> Item
438 [main] INFO org.hibernate.cfg.Configuration - processing association property references
438 [main] INFO org.hibernate.cfg.Configuration - processing foreign key constraints
453 [main] INFO org.hibernate.connection.ConnectionProviderFactory - Initializing connection provider: org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider
906 [main] INFO org.hibernate.cfg.SettingsFactory - RDBMS: HSQL Database Engine, version: 1.8.0
906 [main] INFO org.hibernate.cfg.SettingsFactory - JDBC driver: HSQL Database Engine Driver, version: 1.8.0
922 [main] INFO org.hibernate.dialect.Dialect - Using dialect: org.hibernate.dialect.HSQLDialect
938 [main] INFO org.hibernate.transaction.TransactionFactoryFactory - Using default transaction strategy (direct JDBC transactions)
938 [main] INFO org.hibernate.transaction.TransactionManagerLookupFactory - No TransactionManagerLookup configured (in JTA environment, use of read-write or transactional second-level cache is not recommended)
938 [main] INFO org.hibernate.cfg.SettingsFactory - Automatic flush during beforeCompletion(): disabled
938 [main] INFO org.hibernate.cfg.SettingsFactory - Automatic session close at end of transaction: disabled
938 [main] INFO org.hibernate.cfg.SettingsFactory - JDBC batch size: 15
938 [main] INFO org.hibernate.cfg.SettingsFactory - JDBC batch updates for versioned data: disabled
938 [main] INFO org.hibernate.cfg.SettingsFactory - Scrollable result sets: enabled
938 [main] INFO org.hibernate.cfg.SettingsFactory - JDBC3 getGeneratedKeys(): disabled
938 [main] INFO org.hibernate.cfg.SettingsFactory - Connection release mode: null
938 [main] INFO org.hibernate.cfg.SettingsFactory - Default batch fetch size: 1
938 [main] INFO org.hibernate.cfg.SettingsFactory - Generate SQL with comments: disabled
938 [main] INFO org.hibernate.cfg.SettingsFactory - Order SQL updates by primary key: disabled
938 [main] INFO org.hibernate.cfg.SettingsFactory - Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
938 [main] INFO org.hibernate.hql.ast.ASTQueryTranslatorFactory - Using ASTQueryTranslatorFactory
938 [main] INFO org.hibernate.cfg.SettingsFactory - Query language substitutions: {}
938 [main] INFO org.hibernate.cfg.SettingsFactory - Second-level cache: enabled
938 [main] INFO org.hibernate.cfg.SettingsFactory - Query cache: disabled
938 [main] INFO org.hibernate.cfg.SettingsFactory - Cache provider: org.hibernate.cache.EhCacheProvider
938 [main] INFO org.hibernate.cfg.SettingsFactory - Optimize cache for minimal puts: disabled
938 [main] INFO org.hibernate.cfg.SettingsFactory - Structured second-level cache entries: disabled
953 [main] INFO org.hibernate.cfg.SettingsFactory - Echoing all SQL to stdout
953 [main] INFO org.hibernate.cfg.SettingsFactory - Statistics: disabled
953 [main] INFO org.hibernate.cfg.SettingsFactory - Deleted entity synthetic identifier rollback: disabled
953 [main] INFO org.hibernate.cfg.SettingsFactory - Default entity-mode: pojo
1078 [main] INFO org.hibernate.impl.SessionFactoryImpl - building session factory
1531 [main] INFO org.hibernate.impl.SessionFactoryObjectFactory - Not binding factory to JNDI, no JNDI name configured
1531 [main] INFO org.hibernate.impl.SessionFactoryImpl - Checking 0 named queries
1875 [main] INFO org.hibernate.dialect.Dialect - Using dialect: org.hibernate.dialect.HSQLDialect
1875 [main] INFO org.hibernate.cfg.Configuration - processing extends queue
1875 [main] INFO org.hibernate.cfg.Configuration - processing collection mappings
1875 [main] INFO org.hibernate.cfg.Configuration - processing association property references
1875 [main] INFO org.hibernate.cfg.Configuration - processing foreign key constraints
Hibernate: insert into RssFeed (version, location, id) values (?, ?, null)
Hibernate: call identity()
Hibernate: insert into Channel (version, link, channelId, title, description, lastBuildDate, pubDate, feed, FK_RSS_FEED_ID_PARENT, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, null)
Hibernate: call identity()
Hibernate: update RssFeed set version=? where id=? and version=?
Hibernate: update Channel set FK_RSS_FEED_ID_PARENT=? where id=?
Hibernate: select rssfeed0_.id as id0_, channels1_.id as id1_, rssfeed0_.version as version0_0_, rssfeed0_.location as location0_0_, channels1_.version as version1_1_, channels1_.link as link1_1_, channels1_.channelId as channelId1_1_, channels1_.title as title1_1_, channels1_.description as descript6_1_1_, channels1_.lastBuildDate as lastBuil7_1_1_, channels1_.pubDate as pubDate1_1_, channels1_.feed as feed1_1_, channels1_.FK_RSS_FEED_ID_PARENT as FK10_0__, channels1_.id as id0__ from RssFeed rssfeed0_ left outer join Channel channels1_ on rssfeed0_.id=channels1_.FK_RSS_FEED_ID_PARENT where rssfeed0_.id=?
Hibernate: insert into Item (version, channel, title, post, FK_CHANNEL_ID_PARENT, id) values (?, ?, ?, ?, ?, null)
Hibernate: call identity()
Hibernate: update Channel set version=?, title=?, description=?, lastBuildDate=?, pubDate=?, feed=? where id=? and version=?
Hibernate: update Item set FK_CHANNEL_ID_PARENT=? where id=?
Hibernate: select channel0_.id as id0_, items1_.id as id1_, channel0_.version as version1_0_, channel0_.link as link1_0_, channel0_.channelId as channelId1_0_, channel0_.title as title1_0_, channel0_.description as descript6_1_0_, channel0_.lastBuildDate as lastBuil7_1_0_, channel0_.pubDate as pubDate1_0_, channel0_.feed as feed1_0_, items1_.version as version2_1_, items1_.channel as channel2_1_, items1_.title as title2_1_, items1_.post as post2_1_, items1_.FK_CHANNEL_ID_PARENT as FK6_0__, items1_.id as id0__ from Channel channel0_ left outer join Item items1_ on channel0_.id=items1_.FK_CHANNEL_ID_PARENT where channel0_.id=?
Hibernate: select rssfeed0_.id as id, rssfeed0_.version as version0_, rssfeed0_.location as location0_ from RssFeed rssfeed0_
[/code]