Sample-hibernate-basic » History » Version 35
Henning Blohm, 31.08.2025 15:51
1 | 1 | Henning Blohm | h1. A plain Hibernate on Z2 sample |
---|---|---|---|
2 | 2 | Henning Blohm | |
3 | 33 | Henning Blohm | Note that Hibernate is used in other samples as well, such as [[Sample-jta-plain]], [[Sample-jta-spring]], and others. This sample shows the minimal things to do to use Hibernate as an implementation of the Java Persistence API (<notextile></notextile>"JPA":http://de.wikipedia.org/wiki/Java_Persistence_API<notextile></notextile>). |
4 | 4 | Henning Blohm | |
5 | 33 | Henning Blohm | This sample is stored in the repository "z2-samples.hibernate.basic":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic<notextile></notextile>. |
6 | 5 | Henning Blohm | |
7 | 33 | Henning Blohm | This sample makes use of the [[Hibernate_Add-on|Hibernate Add-on]] and is most likely the best documentation on how to use its supporting functionality. While some of the possibly complex seeming (but only needed once) glue code below is not required when using Spring (for example), as in [[Sample-spring-hibernate]], [[Sample-springds-hibernate]], this sample is most instructive on how Hibernate, Transaction Management, Z2, and the Jetty Web Container integrate with one another while closely sticking to standard descriptors (JPA) and naming (Jakarta EE JNDI/Servlet). |
8 | 14 | Henning Blohm | |
9 | 5 | Henning Blohm | h2. Prerequisites |
10 | |||
11 | 22 | Henning Blohm | {{include(Java Version Requirements)}} |
12 | 21 | Henning Blohm | |
13 | 11 | Henning Blohm | You need to run Java DB as network server on localhost. This is explained next. |
14 | 1 | Henning Blohm | |
15 | 11 | Henning Blohm | The application will create a database "z2-samples" |
16 | 5 | Henning Blohm | |
17 | 11 | Henning Blohm | {{include(How to run Java db)}} |
18 | |||
19 | h2. Run the sample |
||
20 | 5 | Henning Blohm | |
21 | 25 | Henning Blohm | If you have the database, the fastest way to verify whether it runs is: |
22 | 1 | Henning Blohm | |
23 | 25 | Henning Blohm | {{include(Install_sample_prefix)}} |
24 | 5 | Henning Blohm | |
25 | 25 | Henning Blohm | Check out the sample |
26 | 5 | Henning Blohm | |
27 | 33 | Henning Blohm | <pre><code> |
28 | 32 | Henning Blohm | git clone -b v2.10 https://www.z2-environment.net/git/z2-samples.hibernate-basic |
29 | 5 | Henning Blohm | </code></pre> |
30 | 25 | Henning Blohm | |
31 | {{include(Install_sample_postfix)}} |
||
32 | 5 | Henning Blohm | |
33 | 33 | Henning Blohm | When started, go to http://localhost:8080/hibernate-basic . You should see this: |
34 | 10 | Henning Blohm | |
35 | !hibernate-basic.png! |
||
36 | |||
37 | 5 | Henning Blohm | h2. Details |
38 | |||
39 | 33 | Henning Blohm | A lot of the things happening here relate to what is explained in [[How_to_transaction_management|How to transaction management]]. |
40 | 1 | Henning Blohm | |
41 | 33 | Henning Blohm | The assumption of this example is that of a re-use domain module *com.zfabrik.samples.hibernate-basic.domain* that implements a "Thingy Repository" and is used from a web application that is in another module *com.zfabrik.samples.hibernate-basic.web*<notextile></notextile>. The domain module exposes the Thingy Repository as a Z2 component that is bound by the Web app as an environment (ENC) variable and injected into the controller filter by the Web container. |
42 | 7 | Henning Blohm | |
43 | 33 | Henning Blohm | The domain module makes use of Hibernate's JPA implementation and integrates with the transaction management provided by *com.zfabrik.jta*<notextile></notextile>. |
44 | 7 | Henning Blohm | |
45 | Now, step-by-step. |
||
46 | |||
47 | h3. The domain module and its persistence context |
||
48 | |||
49 | 33 | Henning Blohm | The domain module *com.zfabrik.samples.hibernate-basic.domain* defines a persistence unit "thingies" in "java/src.impl/META-INF/persistence.xml":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.domain/java/src.impl/META-INF/persistence.xml<notextile></notextile>, i.e. in its implementation. That makes sense, as the XML file will be looked up with a class loader and we do not intent to retrieve from another module. Or, put differently, the persistence unit is not part of the module's API. |
50 | 7 | Henning Blohm | |
51 | 33 | Henning Blohm | In order to integrate with the built-in transaction management the @persistence.xml@ declares the JTA data source |
52 | 7 | Henning Blohm | |
53 | 33 | Henning Blohm | <pre><code> |
54 | <jta-data-source>osgi:com.zfabrik.samples.hibernate-basic.domain/DB</jta-data-source> |
||
55 | 1 | Henning Blohm | </code></pre> |
56 | |||
57 | 33 | Henning Blohm | and the _JTA Platform_ (Hibernate's transaction management abstraction since v4.3). |
58 | 1 | Henning Blohm | |
59 | 33 | Henning Blohm | <pre><code> |
60 | <property name="hibernate.transaction.jta.platform" value="com.zfabrik.hibernate.Z2JtaPlatform"/>; |
||
61 | 7 | Henning Blohm | </code></pre> |
62 | |||
63 | 33 | Henning Blohm | The former points to the data source component "com.zfabrik.samples.hibernate-basic.domain/DB":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.domain/DB.properties<notextile></notextile>, while the latter makes sure Hibernate can register with the transaction manager implementation that comes built-in with Z2 (other samples, such as [[Sample-jta-plain]], [[Sample-springds-hibernate]] show alternative approaches). |
64 | 12 | Udo Offermann | |
65 | 34 | Henning Blohm | Note the use of the "osgi:" JNDI naming scheme that is an alias to Z2's built-in "component:" JNDI naming schema due to Hibernate's selective support of naming scheme's as of "HHH-15033":https://hibernate.atlassian.net/browse/HHH-15033<notextile></notextile>. |
66 | 7 | Henning Blohm | |
67 | 33 | Henning Blohm | The persistence unit defines only one entity. The Thingy as in "Thingy.java":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.domain/java/src.api/com/zfabrik/samples/hibernate_basic/thingies/Thingy.java<notextile></notextile>. That is an API-exposed type. We use the simplified pattern of exposing persistent objects in the API rather than using Data Transfer Objects (DTOs). |
68 | 1 | Henning Blohm | |
69 | 33 | Henning Blohm | Also, the domain module exposes the interface of the "Thingy Repository":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.domain/java/src.api/com/zfabrik/samples/hibernate_basic/thingies/ThingyRepository.java<notextile></notextile>. This interface is used by the Web application to retrieve, store, and delete thingies. |
70 | 1 | Henning Blohm | |
71 | 33 | Henning Blohm | The implementation of the Thingy Repository, "ThingyRepositoryImpl":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.domain/java/src.impl/com/zfabrik/samples/hibernate_basic/impl/thingies/ThingyRepositoryImpl.java is not a public type. Instead, it is instantiated and held on to via a Z2 component lookup from the Web app on the component "com.zfabrik.samples.hibernate-basic.domain/repository":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.domain/repository.properties<notextile></notextile>. |
72 | 1 | Henning Blohm | |
73 | 33 | Henning Blohm | In ThingyRepositoryImpl, in order to access and re-use the JPA Entity Manager for the persistence unit "thingies" we use EntityManagerUtil from *org.hibernate* with a Entity Manager Factory that we create upon service instantiation and using the user transaction implementation of *com.zfabrik.jta*<notextile></notextile>: |
74 | |||
75 | 35 | Henning Blohm | <pre><code class="java"> |
76 | 14 | Henning Blohm | public class ThingyRepositoryImpl implements ThingyRepository { |
77 | 33 | Henning Blohm | private EntityManagerFactory emf; |
78 | 14 | Henning Blohm | |
79 | 33 | Henning Blohm | /** |
80 | * Create the repo |
||
81 | */ |
||
82 | public ThingyRepositoryImpl() { |
||
83 | /* |
||
84 | * We switch the context class loader so that Hibernate finds our persistence.xml. |
||
85 | * We use the EntityManagerUtil so that Hibernate doesn't freak out in a |
||
86 | * no-Initial-Context-Factory (but URL for lookup) naming environment. |
||
87 | */ |
||
88 | this.emf = ThreadUtil.cleanContextExecute( |
||
89 | this.getClass().getClassLoader(), |
||
90 | new Callable<EntityManagerFactory>() { |
||
91 | @Override |
||
92 | public EntityManagerFactory call() throws Exception { |
||
93 | return EntityManagerUtil.createEntityManagerFactory("thingies"); |
||
94 | } |
||
95 | } |
||
96 | ); |
||
97 | } |
||
98 | 7 | Henning Blohm | |
99 | 33 | Henning Blohm | @Override |
100 | public void store(Thingy thingy) { |
||
101 | this.em().persist(thingy); |
||
102 | } |
||
103 | 7 | Henning Blohm | |
104 | 33 | Henning Blohm | @SuppressWarnings("unchecked") |
105 | @Override |
||
106 | public Collection<Thingy> findAll() { |
||
107 | return this.em().createQuery("select t from Thingy t").getResultList(); |
||
108 | } |
||
109 | 1 | Henning Blohm | |
110 | 33 | Henning Blohm | @Override |
111 | public void delete(int id) { |
||
112 | Thingy t = this.em().find(Thingy.class, id); |
||
113 | if (t != null) { |
||
114 | this.em().remove(t); |
||
115 | } |
||
116 | } |
||
117 | 7 | Henning Blohm | |
118 | 33 | Henning Blohm | // |
119 | // Uses the Entity Manager Util that holds on to EMs created from the passed on EMF |
||
120 | // while the transaction is still open. |
||
121 | // |
||
122 | private EntityManager em() { |
||
123 | return EntityManagerUtil.getEntityManager( |
||
124 | IComponentsLookup.INSTANCE.lookup( |
||
125 | "com.zfabrik.jta/userTransaction", |
||
126 | TransactionManager.class |
||
127 | ), |
||
128 | this.emf |
||
129 | ); |
||
130 | } |
||
131 | 8 | Henning Blohm | } |
132 | </code></pre> |
||
133 | |||
134 | 33 | Henning Blohm | Note that when creating the entity manager factory, we have to make sure the right context class loader is set so that the persistence unit definition will be picked up by Hibernate. This is a general pattern when initializing services in a modular application: You need to distinguish when the service's context matters vs. when the caller's context matters (check out "a blog article on that":http://www.z2-environment.net/blog/2012/07/for-techies-protecting-java-in-a-modular-world-context-classloaders/<notextile></notextile>). |
135 | 8 | Henning Blohm | |
136 | We would normally use the JPA class "Persistence":http://docs.oracle.com/javaee/6/api/javax/persistence/Persistence.html to create an entity manager factory. Due to "HHH-8818":https://hibernate.atlassian.net/browse/HHH-8818 we do need to work around some JNDI issue by using the EntityManagerUtil (see its "source code":https://redmine.z2-environment.net/projects/z2-addons/repository/z2-addons-hibernate/revisions/master/entry/org.hibernate/java/src.api/com/zfabrik/hibernate/EntityManagerUtil.java here). |
||
137 | |||
138 | h3. The web module, transaction boundaries, and service re-use |
||
139 | |||
140 | 33 | Henning Blohm | Let's turn to the Web application in *com.zfabrik.samples.hibernate-basic.web/web*<notextile></notextile>. And let's start with how the Thingy Repository is accessed from the Web app. In this example we do not use Spring or direct lookups, instead we use the Web container provided dependency injection mechanisms. In "WebContent/WEB-INF/jetty-env.xml":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.web/web/WebContent/WEB-INF/jetty-env.xml we bind the result of a JNDI lookup for the repository implementation component to the _Environment Naming Context_ (ENC) variable "repos/thingies". This is java EE mechanics. It means that from within the Web app, the repository is available under the JNDI name "java:comp/env/repos/thingies": |
141 | 8 | Henning Blohm | |
142 | 35 | Henning Blohm | <pre><code class="xml"> |
143 | 34 | Henning Blohm | <Configure id="wac" class="org.eclipse.jetty.ee9.webapp.WebAppContext"> |
144 | <New id="thingyRepository" class="org.eclipse.jetty.plus.jndi.Resource"> |
||
145 | <Arg>repos/thingies</Arg> |
||
146 | <Arg> |
||
147 | <New class="javax.naming.LinkRef"> |
||
148 | <Arg>components:com.zfabrik.samples.hibernate-basic.domain/repository?type=com.zfabrik.samples.hibernate_basic.thingies.ThingyRepository</Arg> |
||
149 | </New> |
||
150 | </Arg> |
||
151 | </New> |
||
152 | </Configure> |
||
153 | 8 | Henning Blohm | </code></pre> |
154 | |||
155 | 33 | Henning Blohm | See also "Jetty JNDI":https://www.eclipse.org/jetty/documentation/current/using-jetty-jndi.html<notextile></notextile>. |
156 | 8 | Henning Blohm | |
157 | Anyway. Now, in the "ControllerFilter":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.web/java/src.impl/com/zfabrik/samples/hibernate_basic/impl/web/ControllerFilter.java we inject the Thingy Repository like this: |
||
158 | |||
159 | 35 | Henning Blohm | <pre><code class="java"> |
160 | 8 | Henning Blohm | public class ControllerFilter implements Filter { |
161 | 33 | Henning Blohm | |
162 | // inject thingies repository (see WEB-INF/jetty-env.xml) |
||
163 | @Resource(name="repos/thingies") |
||
164 | private ThingyRepository thingyRepository; |
||
165 | |||
166 | 8 | Henning Blohm | ... |
167 | } |
||
168 | </code></pre> |
||
169 | |||
170 | Alternatively, if you think this is a little overkill, you might as well use a direct lookup, either with JNDI using the name in the XML or via Z2's component lookup |
||
171 | |||
172 | 35 | Henning Blohm | <pre><code class="java"> |
173 | 8 | Henning Blohm | IComponentsLookup.INSTANCE.lookup("com.zfabrik.samples.hibernate-basic.domain/repository",ThingyRepository.class); |
174 | </code></pre> |
||
175 | |||
176 | Finally a word on transaction management. Transaction boundaries are controlled by the "TransactionFilter":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.web/java/src.impl/com/zfabrik/samples/hibernate_basic/impl/web/TransactionFilter.java contained in the sample. We make use of *TransactionUtil* from *com.zabrik.jta* to wrap the actual web app request in a transaction: |
||
177 | |||
178 | 35 | Henning Blohm | <pre><code class="java"> |
179 | 8 | Henning Blohm | @Override |
180 | 33 | Henning Blohm | public void doFilter(final ServletRequest sreq, final ServletResponse sres, final FilterChain chain) throws IOException, ServletException { |
181 | 8 | Henning Blohm | HttpServletRequest req = (HttpServletRequest) sreq; |
182 | if (req.getDispatcherType()==DispatcherType.REQUEST || req.getDispatcherType()==DispatcherType.ASYNC) { |
||
183 | try { |
||
184 | TransactionUtil.run( |
||
185 | (UserTransaction) new InitialContext().lookup("java:comp/UserTransaction"), |
||
186 | 33 | Henning Blohm | new Callable<Void>() { |
187 | 8 | Henning Blohm | public Void call() throws Exception { |
188 | chain.doFilter(sreq, sres); |
||
189 | return null; |
||
190 | } |
||
191 | 1 | Henning Blohm | } |
192 | ); |
||
193 | 15 | Henning Blohm | } catch (Exception e) { |
194 | throw new ServletException(e); |
||
195 | } |
||
196 | } else { |
||
197 | chain.doFilter(sreq, sres); |
||
198 | } |
||
199 | } |
||
200 | </code></pre> |
||
201 | 33 | Henning Blohm | |
202 | 34 | Henning Blohm | Finally note that we retrieved the transaction manager via the standard Jakarta EE JNDI name @java:comp/UserTransaction@ . Z2 uses Jetty as its Web container implementation. In order to have Jetty bind the transaction manager, we configure the Web server in "environment/webServer/jetty.xml":https://redmine.z2-environment.net/projects/z2-samples/repository/revisions/master/entry/environment/webServer/jetty.xml to retrieve the built-in transaction manager: |
203 | 33 | Henning Blohm | |
204 | 35 | Henning Blohm | <pre><code class="xml"> |
205 | 15 | Henning Blohm | ... |
206 | 33 | Henning Blohm | |
207 | 34 | Henning Blohm | <New id="tx" class="org.eclipse.jetty.ee9.plus.jndi.Transaction"> |
208 | <Arg><Property name="environment" default="ee9"/></Arg> |
||
209 | <Arg><New class="com.zfabrik.tx.UserTransaction"/></Arg> |
||
210 | </New> |
||
211 | |||
212 | 20 | Henning Blohm | ... |
213 | </code></pre> |
||
214 | |||
215 | h2. How this sample makes use of MVNCR |
||
216 | |||
217 | 33 | Henning Blohm | This sample in conjunction with the [[Hibernate_add-on|Hibernate add-on]] is a good example on how to use the Maven component repository (see [[How_to_Access_a_Maven_Repository|How to Access a Maven Repository]]). |
218 | 20 | Henning Blohm | |
219 | The situation is this: |
||
220 | |||
221 | 33 | Henning Blohm | * The add-on (the [[Hibernate_add-on|Hibernate add-on]] in this case) defines the artifacts required but may not define the actual artifact repository to use. After all it may be used with a locally hosted artifact repository. |
222 | 1 | Henning Blohm | * The solution environment (in this case this sample) may define the actual artifact repository but it should not need to repeat all the details on the actual artifact names and versions |
223 | |||
224 | 33 | Henning Blohm | To resolve this we use Maven component repository declarations and Maven component repository fragment declarations. |
225 | 1 | Henning Blohm | |
226 | * The repository declared as part of the sample in "environment/mavenDefault":https://redmine.z2-environment.net/projects/z2-samples/repository/revisions/master/entry/environment/mavenDefault has all the information on where to get artifacts from, while |
||
227 | 33 | Henning Blohm | * the fragment declared in the add-on at "org.hibernate/mvnFragment":https://redmine.z2-environment.net/projects/z2-addons/repository/z2-addons-hibernate/revisions/master/entry/org.hibernate/mvnFragment.properties declares the dependency roots it needs to have resolved from the (yet unknown - from the perspective of the add-on) MVNCR *environment/mavenDefault*<notextile></notextile>. |