InfoQ: Using Hibernate to Support Custom Domain Object Fields
Page 1 of 17
Article
Using Hibernate to Support Custom Domain Object Fields Posted by Enterra Inc. on Nov 05, 2007 11:06 AM Community Java Topics Data Access Tags Hibernate
Introduction When developing corporate-level business applications (Enterprise Scale) customers often requires implementing support for extensibility of the application object model not modifying the system source code. Use of extensible domain model allows for development of new functionality without additional effort and overheads:
RelatedVendorContent Hibernate without Database Bottlenecks Webcast: Applying lean thinking to the governance of software development Gaining Control of Changing Requirements Webcast The Agile Business Analyst: Skills and Techniques needed for Agile Continuous Application Performance eKit - Articles, Discussion Panel, Whitepapers, Demos 1. the application will be used for a more lengthy period 2. the system workflow can be modified over time when changing external factors 3. "setting" the application to fit specifics of an enterprise where it has been deployed. The most simple and cost effective way to achieve the required functionality would be implementing extensible business entities in an application with the support of custom fields.
What is a "Custom Field"? What is a custom field and how the end user benefit from this? A custom field is an attribute of an object which has not been created by the system developer at the development stage but that has been added by the system user into the object when actually using the system not introducing any changes into the source code of the application. Which functionality may be demanded? Let's try to figure out this based on an example of a CRM application. Let's say we have an object "Client". Theoretically this object can have any number of various attributes: several email addresses, many phone numbers, addresses etc. One of these can be used by Sales Department of one company however will be totally ignored by another organization. To enter all possible attributes into the object that may (may not) be used by the end users is wasteful and unjustified. In this case if would be better to allow the user (or administrator) of the system to create the attributes that are necessary for sales managers in a specific organization. For example, administrator can create an attribute "work phone" if this field is actually required or "home address" and etc. Further these fields can be used in the application for example for filtering and searching of data.
Brief Description While implementing the Enterra CRM project the customer set forth the task to support Custom Filed in the application as: "System administrator should be able to create/delete custom fields without the need to restart the system".
http://www.infoq.com/articles/hibernate-custom-fields
11/30/2008
InfoQ: Using Hibernate to Support Custom Domain Object Fields
Page 2 of 17
Hibernate 3.0 framework was used to develop the back end. This factor (technological constraint) was the key that was taken into consideration to implement the requirement.
Implementation In this chapter we will provide key moments of the implementation considering specifics of using Hibernate as the framework.
Environment The implementation demo variant from below was developed using: 1. JDK 1.5 2. Hibernate 3.2.0 framework; 3. MySQL 4.1.
Limitations To make it simpler we will not be using Hibernate EntityManager, Hibernate Annotations. Mapping of persistent objects will be built on xml file mapping. Moreover, it is worth mentioning that when using Hibernate Annotations the sample implementation demo will not be functional since is it based on management by xml file mapping.
Task definition We will have to implement a mechanism allowing for creating/deleting custom fields in real time avoiding the application restart, add a value into it and make sure the value is present in the application database. Besides we will have to make sure that the custom field can be used in queries.
Solution Domain Model We will first need a business entity class which we will experiment with. Let is be Contact class. There will be two persistent fields: id and name. However besides these permanent and unchangeable fields the class should be some sort of construction to store values of custom fields. Map would be an ideal construction for this. Let's create a base class for all business entities supporting custom fields - CustomizableEntity, that contains Map CustomProperties to work with custom fields:
InfoQ.com and all content copyright © 2006-2009 C4Media Inc. InfoQ.com hosted at Contegix, the best ISP we've ever worked with. Privacy policy
http://www.infoq.com/articles/hibernate-custom-fields
11/30/2008
InfoQ: Using Hibernate to Support Custom Domain Object Fields
Page 3 of 17
package com.enterra.customfieldsdemo.domain; import java.util.Map; import java.util.HashMap; public abstract class CustomizableEntity { private Map customProperties; public Map getCustomProperties() { if (customProperties == null) customProperties = new HashMap(); return customProperties; } public void setCustomProperties(Map customProperties) { this.customProperties = customProperties; } public Object getValueOfCustomField(String name) { return getCustomProperties().get(name); } public void setValueOfCustomField(String name, Object value) { getCustomProperties().put(name, value); } }
Listing 1 - base class CustomizableEntity
Inherit our class Contact from this base class: package com.enterra.customfieldsdemo.domain; import com.enterra.customfieldsdemo.domain.CustomizableEntity; public class Contact extends CustomizableEntity { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Listing 2 - Class Contact inherited from CustomizableEntity.
We should not forget about the mapping file for this class:
<property name="name" column="fld_name" type="string"/>
http://www.infoq.com/articles/hibernate-custom-fields
11/30/2008
InfoQ: Using Hibernate to Support Custom Domain Object Fields
Page 4 of 17
Listing 3 - Mapping Class Contact.
Please note that properties id and name are done as all ordinary properties, however for customProperties we use a tag
. Documentation on Hibernate 3.2.0GA says that the point of a dynamic-component is: "The semantics of a mapping are identical to . The advantage of this kind of mapping is the ability to determine the actual properties of the bean at deployment time, just by editing the mapping document. Runtime manipulation of the mapping document is also possible, using a DOM parser. Even better, you can access (and change) Hibernate's configuration-time metamodel via the Configuration object." Based on this regulation from Hibernate documentation we will be building this function mechanism.
HibernateUtil and hibernate.cfg.xml After we are defined with the domain model of our application we have to create necessary conditions for Hibernate framework functioning. For this we have to create a configuration file hibernate.cfg.xml and class to work with the core Hibernate functions. <session-factory> <property name="show_sql">true <property name="dialect"> org.hibernate.dialect.MySQLDialect <property name="cglib.use_reflection_optimizer">true <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/custom_fields_test <property name="hibernate.connection.username">root <property name="hibernate.connection.password"> <property name="hibernate.c3p0.max_size">50 <property name="hibernate.c3p0.min_size">0 <property name="hibernate.c3p0.timeout">120 <property name="hibernate.c3p0.max_statements">100 <property name="hibernate.c3p0.idle_test_period">0 <property name="hibernate.c3p0.acquire_increment">2 <property name="hibernate.jdbc.batch_size">20 <property name="hibernate.hbm2ddl.auto">update
Listing 4 - Hibernate configuration file.
The file hibernate.cfg.xml does not contain anything noticeable except for this string: <property name="hibernate.hbm2ddl.auto">update
Listing 5 - using auto-update.
Later we will explain in details on its purpose and tell more how we can go without it. There are several ways to implement class HibernateUtil. Our implementation will differ a bit from well known due to changes into Hibernate configuration.
http://www.infoq.com/articles/hibernate-custom-fields
11/30/2008
InfoQ: Using Hibernate to Support Custom Domain Object Fields
Page 5 of 17
package com.enterra.customfieldsdemo; import org.hibernate.*; import org.hibernate.mapping.PersistentClass; import org.hibernate.tool.hbm2ddl.SchemaUpdate; import org.hibernate.cfg.Configuration; import com.enterra.customfieldsdemo.domain.Contact; public class HibernateUtil { private static HibernateUtil instance; private Configuration configuration; private SessionFactory sessionFactory; private Session session; public synchronized static HibernateUtil getInstance() { if (instance == null) { instance = new HibernateUtil(); } return instance; } private synchronized SessionFactory getSessionFactory() { if (sessionFactory == null) { sessionFactory = getConfiguration().buildSessionFactory(); } return sessionFactory; } public synchronized Session getCurrentSession() { if (session == null) { session = getSessionFactory().openSession(); session.setFlushMode(FlushMode.COMMIT); System.out.println("session opened."); } return session; } private synchronized Configuration getConfiguration() { if (configuration == null) { System.out.print("configuring Hibernate ... "); try { configuration = new Configuration().configure(); configuration.addClass(Contact.class); System.out.println("ok"); } catch (HibernateException e) { System.out.println("failure"); e.printStackTrace(); } } return configuration; } public void reset() { Session session = getCurrentSession(); if (session != null) { session.flush(); if (session.isOpen()) { System.out.print("closing session ... "); session.close(); System.out.println("ok"); } } SessionFactory sf = getSessionFactory(); if (sf != null) { System.out.print("closing session factory ... "); sf.close(); System.out.println("ok"); } this.configuration = null; this.sessionFactory = null; this.session = null; } public PersistentClass getClassMapping(Class entityClass){
http://www.infoq.com/articles/hibernate-custom-fields
11/30/2008
InfoQ: Using Hibernate to Support Custom Domain Object Fields
Page 6 of 17
Listing 6 - HibernateUtils class.
Alongside with usual methods like getCurrentSession(), getConfiguration(), which is necessary for regular work of the application based on Hibernate, we also have implemented such methods as: reset() and getClassMapping(Class entityClass). In the method getConfiguration(), we configure Hibernate and add class Contact into the configuration. Method reset() has been used to close all used by Hibernate resources and clearing all of its settings: public void reset() { Session session = getCurrentSession(); if (session != null) { session.flush(); if (session.isOpen()) { System.out.print("closing session ... "); session.close(); System.out.println("ok"); } } SessionFactory sf = getSessionFactory(); if (sf != null) { System.out.print("closing session factory ... "); System.out.println("ok"); } this.configuration = null; this.sessionFactory = null; this.session = null; }
sf.close();
Listing 7 - method reset()
Method getClassMapping(Class entityClass) returns object PersistentClass, that contains full information on mapping the related entity. In particular the manipulations with the object PersistentClass allow modifying the set of attributes of the entity class in the run-time. public PersistentClass getClassMapping(Class entityClass){ return getConfiguration().getClassMapping(entityClass.getName()); }
Listing 8 - method getClassMapping(Class entityClass).
Manipulations with mapping Once we have the business entity class (Contact) available and the main class to interact with Hibernate we can start working. We can create and save samples of the Contact class. We can even place some data into our Map customProperties, however we should be aware that this data (stored in Map customProperties) are not saved to the DB. To have the data saved we should provide for the mechanism of creating custom fields in our classs and make it the way Hibernate knows how to work with them. To provide for class mapping manipulation we should create some interface. Let's call it CustomizableEntityManager. Its name should reflect the purpose of the interface managing a business entity, its contents and attributes:
http://www.infoq.com/articles/hibernate-custom-fields
11/30/2008
InfoQ: Using Hibernate to Support Custom Domain Object Fields
Page 7 of 17
package com.enterra.customfieldsdemo; import org.hibernate.mapping.Component; public interface CustomizableEntityManager { public static String CUSTOM_COMPONENT_NAME = "customProperties"; void addCustomField(String name); void removeCustomField(String name); Component getCustomProperties(); Class getEntityClass(); }
Listing 9 - Interface CustomizableEntityManager
The main methods for the interface are: void addCustomField(String name) and void removeCustomField(String name). These should created and remove our custom field in the mapping of the corresponding class. Below is the way to implement the interface:
http://www.infoq.com/articles/hibernate-custom-fields
11/30/2008
InfoQ: Using Hibernate to Support Custom Domain Object Fields
Page 8 of 17
package com.enterra.customfieldsdemo; import org.hibernate.cfg.Configuration; import org.hibernate.mapping.*; import java.util.Iterator; public class CustomizableEntityManagerImpl implements CustomizableEntityManager { private Component customProperties; private Class entityClass; public CustomizableEntityManagerImpl(Class entityClass) { this.entityClass = entityClass; } public Class getEntityClass() { return entityClass; } public Component getCustomProperties() { if (customProperties == null) { Property property = getPersistentClass().getProperty(CUSTOM_COMPONENT_NAME); customProperties = (Component) property.getValue(); } return customProperties; } public void addCustomField(String name) { SimpleValue simpleValue = new SimpleValue(); simpleValue.addColumn(new Column("fld_" + name)); simpleValue.setTypeName(String.class.getName()); PersistentClass persistentClass = getPersistentClass(); simpleValue.setTable(persistentClass.getTable()); Property property = new Property(); property.setName(name); property.setValue(simpleValue); getCustomProperties().addProperty(property); updateMapping(); } public void removeCustomField(String name) { Iterator propertyIterator = customProperties.getPropertyIterator(); while (propertyIterator.hasNext()) { Property property = (Property) propertyIterator.next(); if (property.getName().equals(name)) { propertyIterator.remove(); updateMapping(); return; } } } private synchronized void updateMapping() { MappingManager.updateClassMapping(this); HibernateUtil.getInstance().reset(); // updateDBSchema(); } private PersistentClass getPersistentClass() { return HibernateUtil.getInstance().getClassMapping(this.entityClass); } }
Listing 10 - implementing interface CustomizableEntityManager
First of all we should point out that when creating class CustomizableEntityManager we specify the business entity class the manager will operate. This class is passed as a parameter to designer CustomizableEntityManager:
http://www.infoq.com/articles/hibernate-custom-fields
11/30/2008
InfoQ: Using Hibernate to Support Custom Domain Object Fields
Page 9 of 17
private Class entityClass; public CustomizableEntityManagerImpl(Class entityClass) { this.entityClass = entityClass; } public Class getEntityClass() { return entityClass; }
Listing 11 - class designer CustomizableEntityManagerImpl
Now we should get more interested in how to implement method void addCustomField(String name): public void addCustomField(String name) { SimpleValue simpleValue = new SimpleValue(); simpleValue.addColumn(new Column("fld_" + name)); simpleValue.setTypeName(String.class.getName()); PersistentClass persistentClass = getPersistentClass(); simpleValue.setTable(persistentClass.getTable()); Property property = new Property(); property.setName(name); property.setValue(simpleValue); getCustomProperties().addProperty(property); updateMapping(); }
Listing 12 - creating custom field.
As we can see from the implementation, Hibernate offers more options in working with properties of persistent objects and their representation in the DB. As per the essence of the method: 1) We create class SimpleValue that allow us to denote how the value of this custom field will be stored in the DB in which field and table of the DB: SimpleValue simpleValue = new SimpleValue(); simpleValue.addColumn(new Column("fld_" + name)); simpleValue.setTypeName(String.class.getName()); PersistentClass persistentClass = getPersistentClass(); simpleValue.setTable(persistentClass.getTable());
Listing 13 - creating new column of the table.
2) We create a property of the persistent object and add a dynamic component into it (!), that we have planned to be used for this purpose: Property property = new Property() property.setName(name) property.setValue(simpleValue) getCustomProperties().addProperty(property)
Listing 14 - creating object property.
3) And finally we should make our application perform certain changes in the xml files and update the Hibernate configuration. This can be done via method updateMapping(); It is necessary to clarify the purpose of another two get-methods which have been used in the code above. The first method is getCustomProperties():
http://www.infoq.com/articles/hibernate-custom-fields
11/30/2008
InfoQ: Using Hibernate to Support Custom Domain Object Fields
Page 10 of 17
public Component getCustomProperties() { if (customProperties == null) { Property property = getPersistentClass().getProperty(CUSTOM_COMPONENT_NAME); customProperties = (Component) property.getValue(); } return customProperties; }
Listing 15 - getting CustomProperties as Component.
This method finds and returns object Component corresponding to the tag in the mapping of our business entity. The second method is updateMapping(): private synchronized void updateMapping() { MappingManager.updateClassMapping(this); HibernateUtil.getInstance().reset(); // updateDBSchema(); }
Listing 16 - method updateMapping(). The method is in charge for storing the updated mapping of the persistent class and updates the configuration status of Hibernate to make further changes that we make valid when the changes take effect. By the way we should get back to the string: <property name="hibernate.hbm2ddl.auto">update
of the Hibernate configuration. If this string was missing we would have to launch executing updates of the DB schema using hibernate utilities. However using the setting allows us to avoid this.
Saving mapping Modifications to mapping made in run-time do not save by themselves into the corresponding xml mapping file and to make the changes to get activated at next launch of the application we need to manually save changes to the corresponding mapping file. To do this we will be using class MappingManager the main purpose of which is to save mapping of the designated business entity to its xml mapping file:
http://www.infoq.com/articles/hibernate-custom-fields
11/30/2008
InfoQ: Using Hibernate to Support Custom Domain Object Fields
Page 11 of 17
package com.enterra.customfieldsdemo; import com.enterra.customfieldsdemo.domain.CustomizableEntity; import org.hibernate.Session; import org.hibernate.mapping.Column; import org.hibernate.mapping.Property; import org.hibernate.type.Type; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import java.util.Iterator; public class MappingManager { public static void updateClassMapping(CustomizableEntityManager entityManager) { try { Session session = HibernateUtil.getInstance().getCurrentSession(); Class extends CustomizableEntity> entityClass = entityManager.getEntityClass(); String file = entityClass.getResource(entityClass.getSimpleName() + ".hbm.xml").getPath(); Document document = XMLUtil.loadDocument(file); NodeList componentTags = document.getElementsByTagName("dynamic-component"); Node node = componentTags.item(0); XMLUtil.removeChildren(node); Iterator propertyIterator = entityManager.getCustomProperties().getPropertyIterator(); while (propertyIterator.hasNext()) { Property property = (Property) propertyIterator.next(); Element element = createPropertyElement(document, property); node.appendChild(element); } XMLUtil.saveDocument(document, file); } catch (Exception e) { e.printStackTrace(); } } private static Element createPropertyElement(Document document, Property property) { Element element = document.createElement("property"); Type type = property.getType(); element.setAttribute("name", property.getName()); element.setAttribute("column", ((Column) property.getColumnIterator().next()).getName()); element.setAttribute("type", type.getReturnedClass().getName()); element.setAttribute("not-null", String.valueOf(false)); return element; } }
Listing 17 - the utility to update mapping of the persistent class.
The class literally performs the following: 1. Defines a location and loads xml mapping for the designated business entity into the DOM Document object for further manipulations with it; 2. Finds the element of this document . In particular here we store the custom fields and its contents we change; 3. Delete (!) all embedded elements from this element; 4. For any persistent property contained in our component that is in charge for the custom fields storage, we create a specific document element and define attributes for the element from the corresponding property; 5. Save this newly created mapping file. When manipulating XML we use (as we can see from the code) class XMLUtil, that in general can be implemented in any way though it should correctly load and save the xml file. Our implementation is given at the listing below:
http://www.infoq.com/articles/hibernate-custom-fields
11/30/2008
InfoQ: Using Hibernate to Support Custom Domain Object Fields
Page 12 of 17
package com.enterra.customfieldsdemo; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Document; import org.xml.sax.SAXException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilder; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.Transformer; import javax.xml.transform.OutputKeys; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.dom.DOMSource; import java.io.IOException; import java.io.FileOutputStream; public class XMLUtil { public static void removeChildren(Node node) { NodeList childNodes = node.getChildNodes(); int length = childNodes.getLength(); for (int i = length - 1; i > -1; i--) node.removeChild(childNodes.item(i)); } public static Document loadDocument(String file) throws ParserConfigurationException, SAXException, IOException { DocumentBuilderFactory factory =DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); return builder.parse(file); } public static void saveDocument(Document dom, String file) throws TransformerException, IOException { TransformerFactory tf = TransformerFactory.newInstance(); Transformer transformer = tf.newTransformer(); transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, dom.getDoctype().getPublicId()); transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, dom.getDoctype().getSystemId()); DOMSource source = new DOMSource(dom); StreamResult result = new StreamResult(); FileOutputStream outputStream = new FileOutputStream(file); result.setOutputStream(outputStream); transformer.transform(source, result); outputStream.flush(); outputStream.close(); } }
Listing 18 - XML manipulation utility.
Testing Now when we have all the necessary working code at place we can write tests and see how everything works. The first test will create the custom field "email", create and save the object of the class Contact and define it the "email" property. First let's take a look at the data table tbl_contact. It contains two fields: fld_id, fld_name. The code is provided below:
http://www.infoq.com/articles/hibernate-custom-fields
11/30/2008
InfoQ: Using Hibernate to Support Custom Domain Object Fields
Page 13 of 17
package com.enterra.customfieldsdemo.test; import com.enterra.customfieldsdemo.HibernateUtil; import com.enterra.customfieldsdemo.CustomizableEntityManager; import com.enterra.customfieldsdemo.CustomizableEntityManagerImpl; import com.enterra.customfieldsdemo.domain.Contact; import org.hibernate.Session; import org.hibernate.Transaction; import java.io.Serializable; public class TestCustomEntities { private static final String TEST_FIELD_NAME = "email"; private static final String TEST_VALUE = "[email protected]"; public static void main(String[] args) { HibernateUtil.getInstance().getCurrentSession(); CustomizableEntityManager contactEntityManager = new CustomizableEntityManagerImpl(Contact.class); contactEntityManager.addCustomField(TEST_FIELD_NAME); Session session = HibernateUtil.getInstance().getCurrentSession(); Transaction tx = session.beginTransaction(); try { Contact contact = new Contact(); contact.setName("Contact Name 1"); contact.setValueOfCustomField(TEST_FIELD_NAME, TEST_VALUE); Serializable id = session.save(contact); tx.commit(); contact = (Contact) session.get(Contact.class, id); Object value = contact.getValueOfCustomField(TEST_FIELD_NAME); System.out.println("value = " + value); } catch (Exception e) { tx.rollback(); System.out.println("e = " + e); } } }
Listing 19 - test to creation of the custom field.
This method is responsible for the following: 1. 2. 3. 4. 5.
Creation of CustomizableEntityManager for class Contact; Creation of new custom field named "email"; Further in transaction we create a new contact and give the custom field value "[email protected]"; Save Contact; Get the value of the cusom field "email"
As the result of the execution we can see the following: configuring Hibernate ... ok session opened. closing session ... ok closing session factory ... ok configuring Hibernate ... ok session opened. Hibernate: insert into tbl_contact (fld_name, fld_email) values (?, ?) value = [email protected]
Listing 20 - test result.
In the database the following record can be seen:
http://www.infoq.com/articles/hibernate-custom-fields
11/30/2008
InfoQ: Using Hibernate to Support Custom Domain Object Fields
+--------+---------------------+----------------------+ | fld_id | fld_name | fld_email | +--------+---------------------+----------------------+ | 1 | Contact Name 1 | [email protected] +--------+---------------------+----------------------+
Page 14 of 17
|
Listing 21 - DB result.
As we can see the new field has been created in the run-time and its value successfully saved. The second test creates the query to the DB using the newly created field:
package com.enterra.customfieldsdemo.test; import com.enterra.customfieldsdemo.HibernateUtil; import com.enterra.customfieldsdemo.CustomizableEntityManager; import com.enterra.customfieldsdemo.domain.Contact; import org.hibernate.Session; import org.hibernate.Criteria; import org.hibernate.criterion.Restrictions; import java.util.List; public class TestQueryCustomFields { public static void main(String[] args) { Session session = HibernateUtil.getInstance().getCurrentSession(); Criteria criteria = session.createCriteria(Contact.class); criteria.add(Restrictions.eq(CustomizableEntityManager.CUSTOM_COMPONENT_NAME + ".email", "[email protected]")) List list = criteria.list(); System.out.println("list.size() = " + list.size()); } }
Listing 22 - Query test by the custom field.
Execution result: configuring Hibernate ... ok session opened. Hibernate: select this_.fld_id as fld1_0_0_, this_.fld_name as fld2_0_0_, this_.fld_email as fld3_0_0_ from tbl_contact this_ where this_.fld_email=? list.size() = 1
Listing 23 - Query execution result.
As we can see the custom field that has been created using our technology can easily participate in queries to the DB.
Further Improvements Obviously the implementation we spoke above is rather primitive. It does not reflect all the variety of options that pop up at actual implementation of this functionality. Yet, it shows the general working mechanism of the solution on the technological platform suggested. It is also obvious that the requirement can be implemented using other mechanisms (e.g. code generation) which may be considered in other articles. This implementation supports only String type as Custom Fields however in the real application built with this approach (Enterra CRM) a full support has been implemented as for all primitive types as well as object types (links to business objects) and collection fields. To support custom fields in the part of the user interface the system of meta-descriptors for the custom fields has been implemented which used the user interface generation system. However the mechanism of the generator is a theme for
http://www.infoq.com/articles/hibernate-custom-fields
11/30/2008
InfoQ: Using Hibernate to Support Custom Domain Object Fields
Page 15 of 17
a separate article.
Conclusion As the result of the Enterra CRM team has created, approved and applied in practice the architecture of open object model based on ORM platform Hibernate which allowed for satisfying of the customer requests referring to the application settings under actual need of the end users in the run-time with no necessity to make changes to the source code of the application. Bookmark digg+, reddit+, del.icio.us+, dzone+, facebook+
10 comments
Reply
Worse Than Failure by Greg Helton Posted Nov 6, 2007 1:39 PM Re: Worse Than Failure by Jeppe Cramon Posted Nov 7, 2007 2:26 AM Is Listing 3 broken? by Hiroki Kondo Posted Nov 6, 2007 1:45 PM Re: Is Listing 3 broken? by Diana Plesa Posted Nov 7, 2007 5:17 AM Existing content by Benny Michielsen Posted Nov 12, 2007 4:48 AM Solution with Annotations? by Tom Bostelmann Posted Dec 29, 2007 1:35 PM Re: Solution with Annotations? by Tom Bostelmann Posted Dec 29, 2007 9:50 PM When using oracle iam getting exception by Arif Mohd Posted Feb 19, 2008 6:32 AM Re: When using oracle iam getting exception by Ken Nguyen Posted Mar 13, 2008 9:29 AM Can't remove the custom fields,Why? by nakamula mata Posted Sep 2, 2008 1:59 AM Sort by date descending
Worse Than Failure Nov 6, 2007 1:39 PM by Greg Helton
I've seen this anti-pattern before. Reply
Is Listing 3 broken? Nov 6, 2007 1:45 PM by Hiroki Kondo
Hi. I find a doubtful point in Listing 3. Where does tag start? This is an essencial point in this article. So I recommend as soon as even possible fix it. I read this article using Firefox 2. Reply
Re: Worse Than Failure Nov 7, 2007 2:26 AM by Jeppe Cramon
If you have experience and a better pattern then please share instead of just proclaiming that the proposed solution is an antipattern ;) Reply
Re: Is Listing 3 broken? Nov 7, 2007 5:17 AM by Diana Plesa
http://www.infoq.com/articles/hibernate-custom-fields
11/30/2008
InfoQ: Using Hibernate to Support Custom Domain Object Fields
Page 16 of 17
Hi Hiroki This has been now fixed Reply
Existing content Nov 12, 2007 4:48 AM by Benny Michielsen
What happens with any existing content in the table that is being altered? Reply
Solution with Annotations? Dec 29, 2007 1:35 PM by Tom Bostelmann
This solutions looks great for use in a pluggable architecture. Do you have a solution that utilizes annotations? Reply
Re: Solution with Annotations? Dec 29, 2007 9:50 PM by Tom Bostelmann
Whoops. My apologies. I should have read the article more closely :P Reply
When using oracle iam getting exception Feb 19, 2008 6:32 AM by Arif Mohd
Hi, I tried the example, but getting the following exception.Also the new column is not created in Database.Every time i run a new row is inserted in DB(connection to DB is perfect)but actual functionality i.e, new column is not inserted.Iam using Oracle. configuring Hibernate ... ok log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment). log4j:WARN Please initialize the log4j system properly. session opened. java.net.ConnectException: Connection refused: connect at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.PlainSocketImpl.doConnect(Unknown Source) at java.net.PlainSocketImpl.connectToAddress(Unknown Source) at java.net.PlainSocketImpl.connect(Unknown Source) at java.net.Socket.connect(Unknown Source) at java.net.Socket.connect(Unknown Source) at sun.net.NetworkClient.doConnect(Unknown Source) at sun.net.www.http.HttpClient.openServer(Unknown Source) at sun.net.www.http.HttpClient.openServer(Unknown Source) at sun.net.www.http.HttpClient.(Unknown Source) at sun.net.www.http.HttpClient.New(Unknown Source) at sun.net.www.http.HttpClient.New(Unknown Source) at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(Unknown Source) at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source) at sun.net.www.protocol.http.HttpURLConnection.connect(Unknown Source) at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source) at org.apache.xerces.impl.XMLEntityManager.setupCurrentEntity(Unknown Source) at org.apache.xerces.impl.XMLEntityManager.startEntity(Unknown Source)
http://www.infoq.com/articles/hibernate-custom-fields
11/30/2008
InfoQ: Using Hibernate to Support Custom Domain Object Fields
Page 17 of 17
at org.apache.xerces.impl.XMLEntityManager.startDTDEntity(Unknown Source) at org.apache.xerces.impl.XMLDTDScannerImpl.setInputSource(Unknown Source) at org.apache.xerces.impl.XMLDocumentScannerImpl$DTDDispatcher.dispatch(Unknown Source) at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source) at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)closing session ... ok closing session factory ... ok configuring Hibernate ... at org.apache.xerces.parsers.DOMParser.parse(Unknown Source) at org.apache.xerces.jaxp.DocumentBuilderImpl.parse(Unknown Source) at javax.xml.parsers.DocumentBuilder.parse(Unknown Source) at com.enterra.customfieldsdemo.XMLUtil.loadDocument(XMLUtil.java:40) at com.enterra.customfieldsdemo.MappingManager.updateClassMapping(MappingManager.java:23) at com.enterra.customfieldsdemo.CustomizableEntityManagerImpl.updateMapping (CustomizableEntityManagerImpl.java:57) at com.enterra.customfieldsdemo.CustomizableEntityManagerImpl.addCustomField (CustomizableEntityManagerImpl.java:40) at com.enterra.customfieldsdemo.test.TestCustomEntities.main(TestCustomEntities.java:21) ok session opened. Hibernate: select hibernate_sequence.nextval from dual Hibernate: insert into tbl_contact (fld_name, fld_id) values (?, ?) value = [email protected] Reply
Re: When using oracle iam getting exception Mar 13, 2008 9:29 AM by Ken Nguyen
Actually you can build this extension into your data model without going through the actual adding of new columns in your existing table by separating meta data and actual data store. It may make your manipulation on service layer slightly more complicated but it gives you a lot of flexibility Reply
Can't remove the custom fields,Why? Sep 2, 2008 1:59 AM by nakamula mata
I have done the source code example,Now I can add custom fields successfully. But I can't remove the added custom fields, the custom fields are still in the table of database. Why? How can I remove the added custom fields in both hibernate mapping and table of database? Reply
http://www.infoq.com/articles/hibernate-custom-fields
11/30/2008