How do I inject Hibernate ClassLoaderService into Spring Boot? - java

Hi I need to pass my own ClassLoaderServiceImpl into Hibernate. The issue is that I cannot figure out how to pass it into Hibernate over Spring Boot. How would I do it?
Here is what I got:
ClassLoaderServiceImpl serviceImpl = new ClassLoaderServiceImpl(customClassLoader);
// Magical code that injects serviceImpl into Spring Boot, which will give it to Hibernate
Any help is much appreciated!

That could be tricky.
you need to use specific EntityManagerFactoryBuilderImpl constructor to inject your own implementation of ClassLoaderServiceImpl
spring-orm uses another constructor which does not fit your needs: SpringHibernateJpaPersistenceProvider - thus, you need to override/inherit SpringHibernateJpaPersistenceProvider
next you need to override HibernateJpaVendorAdapter#getPersistenceProvider
after that you will need to override boot auto-configurations.

Related

Multiple Constructor injection ambiguity with spring boot

I am trying to learn to migrate one spring XML based application to spring boot application and wondering with one scenario where we have multiple constructors in a class and wish to inject all these using spring annotation.
I do understand and implemented the way using XML based configuration but confused with which annotation/way to inject multiple constructors.
I tried referring to few forums like : Ambiguity Regarding Spring Constructor Injection but no luck with spring boot.
Could anyone please help on this please?
As it was mentioned in comments you can use #Configuration
#Configuration
public class Config {
#Bean
public Employee employee() {
return new Employee(10,"100");
}
}

How to set up custom behavior of spring data on a CDI environment

So, I have an application running on WildFly10, which uses JSF, Spring (DI), JPA, Spring Data;
Right now we're trying to move it to CDI and remove Spring(DI). For now we'll keep Spring Data.
So, I set up CDI and made an EntityManager producer.
#Produces
#Dependent
#PersistenceContext
public EntityManager entityManager;
So, I'm able to inject repositories with CDI and all.
However on my original environment we had a custom repository factory,that was defined in my SpringConfiguration like this:
#EnableJpaRepositories(basePackages = {"com.foo.repository" }, repositoryFactoryBeanClass=CustomJpaRepositoryFactoryBean.class)
So, the question is, how can I define this repositoryFactoryBeanClass=CustomJpaRepositoryFactoryBean.class on a CDI environment?
The current implementation doesn't allow the configuration of the JpaRepositoryFactoryBean as one can see from the code where it gets instantiated.
So I guess you have the following options:
reimplement the instantiation process.
open a feature request.
do 2. and 1. in a reusable way and submit the result as a PR for the issue.
When trying to solve this problem I found that the custom impl was not being picked up. The solution suggested in this question helped me however: https://stackoverflow.com/a/38541669/188624
Basically is uses Java8 default interface method to provide the additional functionality. I had to use the "CDI.current().select" method to get hold of the entity manager though as property injection of course won't work.
I tested with Spring Data JPA 2.0.0

What is the equivalent of #DataJpaTest if I just want to test JdbcTemplate code?

Spring Boot 1.4 offers some fantastic testing improvements. One is the #DataJpaTest annotation where it wires up just the parts needed for JPA testing. What would the equivalent look like for just wiring up the parts needed for JdbcTemplate tests?
I'm fine constructing my own composite annotation that mimics the #DataJpaTest one.
Good question. Ironically enough, that one was raised during the testing talk yesterday at SpringOne Platform. Let's see what it takes to implement such dedicated test annotation.
TL;DR check the code on github
First of all you need to create the annotation. This annotation reuses some bits from the spring-boot-test-autoconfigure module. You may want to auto-configure an in-memory database (like DataJpaTest does). You also want to make sure that caching is configured and disabled by default (in case you have #EnableCaching on your Spring Boot application). You also want that all your tests are #Transactional by default so you should add that.
Next, you want that slicing effectively kicks in. All you need at this point is a DataSource, a JdbcTemplate, database migrations (flyway/liquibase) and a transaction manager to process #Transactional. To avoid the other auto-configurations to kick in you should add the following:
#OverrideAutoConfiguration(enabled = false)
Then, you want to explicitly enable the auto-configurations above. In order to do so, you add #ImportAutoConfiguration and you add the following content in META-INF/spring.factories
# AutoConfigureDataJpa auto-configuration imports
com.example.test.autoconfigure.jdbc.DataJdbcTest=\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
The key in spring.factories should match the FQN of your annotation. Whenever Spring Boot finds #ImportAutoConfiguration with no extra attributes, it will look for a key matching the annotation type in spring.factories.
Next up you want to be able to include additional components (component scan) with a filter. In order to do that, you can add #TypeExcludeFilters(DataJdbcTypeExcludeFilter.class) where DataJdbcTypeExcludeFilter is pretty much the same thing as DataJpaTypeExcludeFilter (so we might want to extract a common class for that).
Once you've done that, you only need to add your annotation and your JdbcTemplate is auto-configured for you
#RunWith(SpringRunner.class)
#DataJdbcTest
public class DataJdbcSampleTests {
#Autowired
private JdbcTemplate jdbcTemplate;
...
}
I think the option will be #JdbcTest, you could found further info on doc.

Pre-defined beans in Spring Boot

I want to create a simple app built on Spring Boot. I don't have experience with the framework, and this issue is beyond me.
I want to use the Security module in my app, particularly the org.springframework.security.authentication.encoding.ShaPasswordEncoder class. I want to get this autowired as a bean.
How do I define that in Spring Boot? For instance, this answer explains how to use it in "regular" Spring - defining the bean in a XML file. However, when I was reading the Boot overview, it stated that there is no need for XML setup, so is it possible to somehow do this in code, not configuration? What is the Boot-ish way?
I have tried just using this code to get the encoder class.
#Autowired
private ShaPasswordEncoder passwordEncoder;
But I get an exception: org.springframework.beans.factory.NoSuchBeanDefinitionException -- it's not defined, but how do I define it?
Thanks
The beans can be defined in-code like this:
#Bean
public ShaPasswordEncoder passwordEncoder() {
return new ShaPasswordEncoder();
}
This method will create a bean named "passwordEncoder" which will be managed by Spring. It is the equivalent of the XML-styled
<bean class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" id="passwordEncoder" />
You can put this method in the #SpringBootApplication-annotated class, or any class annotated with #Configuration.
More info here

Can I inject a Java object using Spring without any xml configuration files?

I want to inject a plain java object using Spring programmatically without using any xml configuration. Want to inject fields/methods annotated with tags Like #EJB, #PostConstruct etc. Is that possible? Thanks!
Creating an ApplicationContext without XML (using AnnotationConfigApplicationContext)
With AnnotationConfigApplicationContext, you don't need any XML at all. You create the Application context programatically and either
a) manually register annotated classes
appContext.register( MyTypeA.class,
MyTypeB.class,
MyTypeC.class );
b) or scan the classpath for annotated classes
appContext.scan(
"com.mycompany.myproject.mypackagea",
"com.mycompany.myproject.mypackageb"
)
If you use one of the convenience constructors
AnnotationConfigApplicationContext(Class<?> ... annotatedClasses)
or
AnnotationConfigApplicationContext(String ... basePackages)
the context is created and refreshed automatically, otherwise you need to call the refresh() method manually after adding the classes or packages.
Autowiring existing non-Spring beans (using AutowireCapableBeanFactory)
For autowiring an existing bean I think the preferred idiom is to use
appContext.getAutowireCapableBeanFactory().autowireBean(existingBean)
Or, if you want more control, use
appContext.getAutowireCapableBeanFactory()
.autowireBeanProperties(
existingBean,
autowireMode,
// e.g. AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE
dependencyCheck
)
For further reference, see
ApplicationContext.getAutowireCapeableBeanFactory()
AutowireCapeableBeanFactory.autowireBean(Object existingBean)
AutowireCapeableBeanFactory.autowireBeanProperties(Object
existingBean, int autowireMode,
boolean dependencyCheck)
Yes, you can annotate any POJO with #Component, #Service, #Controller, or #Respository (depending on its responsibilities), and it becomes a spring bean. You just have to put this line into the applicationContext.xml:
<context:component-scan base-package="org.yourbasepackage" />
You can also use #PostConstruct and #PreDestroy instead of the xml init-method and destroy-method.
Update: There is a project called spring-javaconfig. Parts of it have become part of the core spring and you can see more details here. In short, it allows you to use java classes instead of xml for configuring your beans.
The documentation around annotation-based Spring configuration can be found here. You will need a minimal amount of XML, so that Spring knows to look for annotation-based configuration:
<context:component-scan base-package=".." />
Once that is done, you can use the #Autowired annotation to set up your beans.

Categories

Resources