How to Integrate Spring 4 with Hibernate Search 5? - spring

I have already integrate Spring MVC+ Spring Framework 4 + Hibernate ORM 4.
Now I want to use full text search in hibernate search.
So, How to Integrate Spring Framework 4 with Hibernate Search 5?

According to the official documentation this should be as simple as:
Add Hibernate Search JAR to the application.
Add <property name="hibernate.search.default.directory_provider" value="filesystem"/> and <property name="hibernate.search.default.indexBase" value="/var/lucene/indexes"/> to the Hibernate configuration. Alternatively, you can choose a different provider.
Annotate the entities and fields you want to index.
If using the Hibernate Session directly, obtain a FullTextSession as Search.getFullTextSession(sessionFactory.getCurrentSession()), or if using an EntityManager, obtain a FullTextEntityManager as Search.getFullTextEntityManager(entityManager). It is assumed that sessionFactory or entityManager is injected using Spring.
Start searching. Entity instances are automatically indexed on persist so no special steps are required for generating the search indexes.
Give this a try and if you face any specific problem you can raise them as separate questions.

Related

Spring boot application and hibernate are using different naming strategies

This is very strange.
I am using the spring.jpa.generate-ddl=true to create the tables in my database. When spring does this, the table names are snake case.
For example, the table for MyClass becomes my_class.
Next, I exported the schema from Hibernate using this code:
Export schema from Hibernate
When I call the code, the resulting sql has table names in camel case with the first letter capitalized. So, the table for MyClass is MyClass.
Why would they generate differently?
How do I get them to be the same?
The table names are different because Spring configures Hibernate to use a different naming strategy. The naming strategy defines how Hibernate generates the logical name of an attribute or entity and how to map them to the physical name in the database. I explain that in more detail in the Naming Strategy Guide on my blog.
You have multiple options to ensure both of your setups use the same naming strategy:
If you're using a Hibernate version >= 5.5.4, you can configure it to use the CamelCaseToUnderscoresNamingStrategy. That's the one that Spring is using by default:
<persistence>
<persistence-unit name="my-persistence-unit">
...
<properties>
...
<property name="hibernate.physical_naming_strategy"
value="org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy"/>
</properties>
</persistence-unit>
</persistence>
If you're using an older Hibernate version, you might want to change Spring's naming strategy to Hibernate's default strategy. You can do that by setting the following property in your application.properties file:
spring.jpa.properties.hibernate.implicit_naming_strategy=default
If you're using an older Hibernate version and want to use Spring's naming strategy, you have to implement a custom naming strategy. This isn't complex, and I explain how to do it in my blog post, but I would choose one of the previously mentioned solutions.

How to register a hibernate typedescriptor in a "classic" Spring 5 application with jpa entitymanager

I have a classic spring 5 application (NO spring boot). For a custom basic type i have created a typedescriptor by subclassing AbstractTypeDescriptor according to Hibernate 5.2 Documentation - 2.3.5. Explicit BasicTypes. I am using hibernate via an jpa entitymanager. I have two spring beans configured for that: a LocalContainerEntityManagerFactoryBean and a HibernateJpaVendorAdapter.
Now i am a bit lost, how to register the typedescriptor during startup of the application. The docs mention an approach using a hibernate configuration object. But i have no idea, how to get this? Any help appreciated!

Is it possible to use Cache2k as hibernate second level cache and also as a spring cache manager?

I'm working with spring based application (not spring boot) and I'm trying to introduce cache2k as a spring cache manager.
Currently cache2k is used as a Hibernate second level cache by setting the following properties
hibernate.cache.use_second_level_cache = true
hibernate.cache.region.factory_class = org.hibernate.cache.jcache.JCacheRegionFactory
hibernate.javax.cache.provider = org.cache2k.jcache.provider.JCacheProvider
with the following cache2k.xml configuration file (only the relevant part related to the example)
<cache2k xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='https://cache2k.org/schema/v1.x'
xsi:schemaLocation="https://cache2k.org/schema/v1.x https://cache2k.org/schema/cache2k-core-v1.x.xsd">
<!-- The configuration example for the documentation -->
<version>1.0</version>
<skipCheckOnStartup>true</skipCheckOnStartup>
<ignoreMissingCacheConfiguration>true</ignoreMissingCacheConfiguration>
<defaults>
<cache>
<entryCapacity>100</entryCapacity>
</cache>
</defaults>
<templates>
<cache>
<name>lookupTable</name>
<expireAfterWrite>1d</expireAfterWrite>
<entryCapacity>50_000</entryCapacity>
</cache>
</templates>
<caches>
<cache>
<name>AdvertisingCategoryCache</name>
<include>lookupTable</include>
</cache>
</caches>
Now I want to introduce a Spring cache manager and in the cache2k documentation there're enough information in order to introduce it as a spring cache manager also with the following code
#EnableCaching
...
...
#Bean
public CacheManager cacheManager() {
return new SpringCache2kCacheManager();
}
The final goal is to reuse the existing hibernate second level cache also in the spring caching layer when needed but when calling the following method
#Cacheable(cacheNames = "AdvertisingCategoryCache")
#Override
public AdvertisingCategory findById(Long id) {
// call to the repository
}
I get the following error
Cache already created: 'AdvertisingCategoryCache'
The point is that I know that the cache is already created. My need is to reuse the existing one.
How can I do that?
P.S. The example is very easy and for sure I can directly remove the #Cacheable method, but I've used that in order to provide an easy explanation of my situation.
Edit: since you are not using Spring Boot, you need to make sure to set the property that links the cache manager with Hibernate.
First of all you need to use JCache so you'll have to replace your custom cache configuration to use JCache (Hibernate does not provide a cache abstraction implementation for cache2k).
You should have some sort of custom JPA setup that configures the EntityManagerFactory. In that setup, makes sure to inject the CacheManager that you've created. If you have an injection point, the context will make sure to fully resolve the CacheManager before attempting to configure Hibernate (which is definitely what you want here).
Once you've done that, add the following Hibernate property:
hibernateProperties.put(ConfigSettings.CACHE_MANAGER, cacheManager.getCacheManager());
Where cacheManager is the JCacheCacheManager (the Spring implementation wrapping the native javax.cache.CacheManager).
Things are easier if you use Spring Boot. First of all, you should make sure to let Spring Boot configure the cache manager rather than doing it yourself. Since you are using JCache for Hibernate, just use the same mechanism in Spring Boot as it is totally transparent anyway (we'll wrap the JCache CacheManager in the right abstraction behind the scenes).
If you do that, Spring Boot will make sure to boostrap the JCache cache manager before hibernate starts. There is also a dediced how-to that explains how to configure the integration between the two.
Once you've done that, the same cache manager will be shared.

How do I change my configuration to a different data source?

I went through the Data Access With Spring tutorial and the in memory database they use in step 3 is working. But, I'm not clear on what I need to add/change to get it to query my development (Oracle) database now?
I want to use Hibernate, do I still need this JPAConfiguration class or would I have something Hibernate specific?
Please don't just post a link to the Hibernate reference. I'm reviewing that as well, but since I'm also using Spring, it's not clear to me the proper way to load the hibernate.cfg.xml and inject the Hibernate session in that context.
Don't be blocked by the fact that the class is called JPAConfiguration. You need to understand what the class does. Note that it has the annotation #Configuration which you can use along with AnnotationConfigApplicationContext to produce a Spring bean context.
That functionality is described in the Spring documentation for The IoC container.
What you need to change is how your DataSource and EntityManagerFactory beans are created. You'll need to use a DataSource that gets Connection instances from a JDBC Driver that supports Oracle databases.

How to enable load time / runtime weaving with Hibernate JPA and Spring Framework

I'm using Hibernate as a JPA provider (I'm using its EntityManagerFactory instead of its SessionFactory) in a Spring Framework application. I managed to get Spring Framework's load time weaving support working, so I'm past that hurdle.
I need to enable lazy loading of byte[] and #ManyToOne properties on an entity. I understand how to instrument (weave) my entities at build time using Hibernate's ant task, but I'd like to instrument my entities at runtime instead (load time weaving). I've seen references to in on several Google search results, but no actual instructions for enabling it. What property do I need to set to instruct Hibernate that it can instrument my entities at runtime?
After considerable reading of code and debugging, I figured this out. It's a shame the Hibernate ORM documentation doesn't include this information. (To be fair, the Hibernate EntityManager documentation does, but it's not easily found. The Hibernate instructions on "Using lazy property fetching" only says, "Lazy property loading requires buildtime bytecode instrumentation." It does not mention that you can use runtime instrumentation with a Hibernate EntityManager property.)
The first thing you must do is set the "hibernate.ejb.use_class_enhancer" JPA property to "true" (String). This tells Hibernate that it may use the "application server" class transformation by calling addTransformer on the PersistenceUnitInfo instance. The "application server" class transformation is really Spring's LoadTimeWeaver. If you are using Spring's Java configuration and LocalContainerEntityManagerFactoryBean, and Hibernate is a compile-time dependency, you could use the AvailableSettings.USE_CLASS_ENHANCER constant instead of the string-literal "hibernate.ejb.use_class_enhancer" (which would make it typo-resistant).
If you are using Spring's Java configuration, there is an additional step you must take until SPR-10856 is fixed. LocalContainerEntityManagerFactoryBean's setLoadTimeWeaver method is not called automatically like it should be, so you must call it manually. In your #Configuration class, just #Inject or #Autowire a LoadTimeWeaver instance and call setLoadTimeWeaver manually when you are creating the LocalContainerEntityManagerFactoryBean.
With these steps taken, I'm now using Hibernate's runtime entity bytecode instrumentation with Spring Framework in Tomcat.
I have the similar problem. I followed the steps you have mentioned to setup the weaver successfully. I created run time entity using byte buddy with annotations. And loading this class at runt time. Created instance of the same using reflection and trying to persist. But hibernate complains as,
java.lang.IllegalArgumentException: Unknown entity:
I believe the run time entity which I created is not enhanced and hibernate is complaining the same.

Resources