Dear @snicoll and others,

I see a potential problem with HazelcastJpaDependencyAutoConfiguration. As the comment says: Additional configuration to ensure that EntityManagerFactory beans depend-on the hazelcastInstance bean.

The issue with this that it is not possible to use MapStore implementations backed by JPA. The reason is that the EntityManager cannot be injected into a MapStore implementation, since it is not yet created (first HazelcastInstance must be created). But MapStore is needed to create the Config bean, which is needed for the HazelcastInstance...

So my HazelcastConfig looks like this:

@Configuration
public class HazelcastConfig {

    @Bean
    public Config config(TradeMapStore tradeMapStore) {
        return new Config()
                .addMapConfig(
                        new MapConfig("trades")
                                .setMapStoreConfig(
                                        new MapStoreConfig()
                                                .setImplementation(tradeMapStore)
                                                .setWriteDelaySeconds(0) // write-through
                                )
                );
    }

And the MapStore impl:

@Repository
public class TradeMapStore implements MapStore<Long, Trade> {

    @PersistenceContext
    private EntityManager em;

    [...]
}

What do you suggest to circumvent this issue?

Thanks!

Comment From: messo

Since HazelcastJpaDependencyAutoConfiguration is not public I can not exclude from auto-configuration using the exclude attribute of @SpringBootApplication. :-(

I believe the reason of this default dependency, is that you might want to use hazelcast as 2nd-level cache for JPA, but that is only one of the use-cases. You might want to use hazelcast as your primary data source with persistence layer provided by JPA. The latter is impossible currently and it cannot be disabled :-(

Comment From: snicoll

Yep, that's unfortunate indeed. You can still exclude it by name (SpringBootApplication has an excludeName property you can use to provide a FQN). Please give that a try.

You are right, this auto-configuration was introduced to make sure that Hazelcast is available before Hibernate starts (otherwise you can't use it as 2nd level cache). I wasn't really aware of that other use case obviously. Do you think we could tune this auto-configuration to reflect that you want to use Hazelcast as the primary data-source? Could you share a super simple sample that demonstrates this use case please?

If you have the name of a property that reflects precisely that use case, we could also expose a property to switch to control how this auto-configuration operates. In your case, I guess you need some kind of auto-configuration that makes sure hibernate is available before Hazelcast then!

Comment From: vpavic

@snicoll you can take a look at MapStore example in Hazelcast documentation.

Hazelcast even used to have support for Spring Data JPA integration and such use case, although it was just a single class.

IMO a configuration property should be available to support this use case rather than having to exclude parts of auto-configuration.

Comment From: messo

Thanks for the really quick response.

Yes, just before I got sad that I need to leave out spring-boot for this particular project I have found that I can provide classes by name, which works flawlessly. Thanks!

I agree with you and @vpavic, a property would be perfect, not sure about the naming and the purpose? (Which use-case should be 'default'?)

I have created a tiny working example which demonstrates the use-case: https://github.com/messo/spring-boot-hazelcast

Please let me know if there is anything more I can provide to help.

Comment From: snicoll

That helps, thank you. So we have such link on the caching support as well so we need to take that into account.

CacheAutoConfiguration#CacheManagerJpaDependencyConfiguration adds a reference so that the CacheManager is fully loaded before the EntityManager (Hibernate 2nd level cache use case).

We have the same link in the Hazelcast support so if we want to fully address this concern we need to fix that in two places.

Current proposal: - introduce a spring.hazelcast.mode with a HazelcastMode enum that can be HIBERNATE_CACHE or PRIMARY_STORE. This would flip the dependency order - introduce a spring.cache.l2.enabled that would be enabled by default. Disabling this means that we should disable the link that is added if hibernate is available.

The second property can also be used tot let Spring Boot auto-configure the Hibernate 2nd level cache support: it is a feature that we don't have right now and that I do not intend to implement in the 1.3 line. So maybe we'll have to wait for that and provide another way to disable that link for now.

Comment From: messo

The HazelcastMode enum sounds promising.

However I am not sure what is the role of the second attribute. Is the enum not adequate? I mean if you set it to HIBERNATE_CACHE you want to use Hazelcast for Hibernate L2 cache layer, which implicitly means spring.cache.l2.enabled = true, on the other hand if you set the value of the enum to PRIMARY_STORE you do not want to use it for caching (spring.cache.l2.enabled = false?), however you might want to use Hibernate (or any other JPA impl) to persist some data, or to access persisted data (either by hand, or by implementing MapStore).

Bare with me, but I could also imagine a 3rd use-case which is a mixed one -- not sure if it is a real one, or if it can be implemented :) What if one has some data which is located primarily in Hazelcast (and persisted to database using Hibernate, from time-to-time) -- to utilise MapReduce-like operations, but also some other master data-like entities which are not that important to be stored fully in an in-memory data grid, but would be nice if they could be located in L2 cache for faster usage in Hazelcast, transparently. What do you think? Is it a real use-case? If yes, can it be achieved using the same HazelcastInstance? Or other magic tricks -- two different instance, magic proxying, late(r) setter injection?

Comment From: snicoll

The cache thing does not care about Hazelcast. It's making sure the CacheManager is fully initialized before the persistence layer starts (be it Hazelcast, ehcache or whatever). If you don't use the caching infra for L2 then that link is not needed. That's essentially what I am trying to represent with that second property.

I don't know about your third use case and my head hurts right now. You can't have them both so I'd say you need a separate HazelcastInstnace for the second case. The problem is that the cache auto-configuration has already a hard link on the main Hazelcast support (to check what it has to do) so you'll have to resort to manual config in this case. Manual config = back off.

Comment From: messo

Oh, I see now. Thanks for the clarification ;) Yeah probably the third idea is kinda exotic to say the least. ;)

Comment From: snicoll

OK so we just discussed this and exposing that property just for the sake of the link is a bit weird (and probably does not reflect what's actually happening). Adding a more precise property such as spring.hazelcast.require-hibernate is not better either.

I want to change the code in such a way that creating your own HazelcastInstance make sure that the code will backoff. Once I fixed that, you can create your own HazelcastInstance if you deviate from Spring Boot's default.

We may revisit this in 1.4 so that you can still benefit from the auto-config and have things started in the expected order for your use case.

Comment From: snicoll

See #4158

Comment From: wimdeblauwe

Just ran into the same issue and it was not directly clear how to fix it, so in case anyone else wonders, you need to change:

@SpringBootApplication

to

 @SpringBootApplication(exclude = HazelcastJpaDependencyAutoConfiguration.class)

Comment From: lukass77

thanks !! @wimdeblauwe , this solve exactly the same issue when trying to autowired a spring-data jpa repository . it seems that this issue which is open today has the same root cause https://github.com/spring-projects/spring-boot/issues/15359