I want to have an #Entity that is only used for testing. This is because I want to test a #MappedSupertype without creating a dependency to a real entity that extends it.
The source file is in src/test/java but when running the application in Eclipse, the entity is discovered (and for example creates a table on schema export). Is there something like #Profile("test") where I can configure the entity outside of the application (i.e. in the test source)?
Place your entity src/test/java and it is naturally not registered into Hibernate in production, because test folder is not visible to production classes
Related
Scenario:
I'm supporting an Enterprise application that runs in Wildfly10. The application (.war) uses J2EE technologies (EJBs, JPA, JAX-RS) and SpringBoot features (like, SpringMVC, SpringRest, SpringData, SpringRestData) ... Both stacks co-exists "happily" because they don't interact between them; however, they do share common classes, like utility or Entity Classes (the stacks map to the same database model). Why the application uses those stacks is out the scope of the question.
Currently, I'm trying to improve the performance of a #RestController that pulls some data from the database using a JPA Spring Repository. I found that we're suffering the N + 1 queries problem when calling the #RestController. In past projects (where there were only J2EE technologies), I have used the #BatchSize hibernate annotation to mitigate this problem with total success.
But, in this project, Spring seems to be skipping such annotation. How do I know that? Because I turned on the hibernate SQL logging (hibernate.show_sql) and I can see the N + 1 queries is still happening ...
Key Points:
Here are some insights about the application that you must know before providing (or trying to guess) any answer:
The application has many sub-modules encapsulated as libraries inside WAR file (/WEB-INF/lib) ... Some of these libraries are the jars that encapsulate the entity classes; others are the jars that encapsulate the REST Services (that could be JAX-RS services or Spring Controllers).
The Spring configuration is done in the classes defined in the WAR artifact: in there, we have a class (that extends from SpringBootServletInitializer) annotated with #SpringBootApplication and another class (that extends from RepositoryRestConfigurerAdapter) annotated with #Configuration. Spring customization is done is such class.
The application works with multiple datasources, which are defined in the Wildly server. Spring DATA JPA must address any query pointing to the right datasource. To accomplish this requirement, the application (Spring) was configured like this:
#Bean(destroyMethod="")
#ConfigurationProperties(prefix="app.datasource")
public DataSource dataSource() {
// the following class extends from AbstractRoutingDataSource
// and resolve datasources using JNDI names (the wildfly mode!)
return new DataSourceRouter();
}
#Bean("entityManagerFactory")
public LocalContainerEntityManagerFactoryBean getEntityManagerFactoryBean() {
LocalContainerEntityManagerFactoryBean lemfb;
lemfb = new LocalContainerEntityManagerFactoryBean();
lemfb.setPersistenceUnitName("abcd-pu");
lemfb.setDataSource(dataSource());
return lemfb;
}
The last #Bean declaration favors the use of a persistence.xml file, which we do have in the route /WEB-INF/classes/META-INF/ (i.e. Spring does find this file!) ... In such file, we define our domain classes, so that Spring JPA can see such entities. Also, we can define special JPA properties like: hibernate.show_sql and hibernate.use_sql_comments without issues (this is how I detected the N + 1 queries problem in the first place) ...
What I have done so far?
I tried to add the #BatchSize annotation to the problematic collection. No luck!
I created a new JAX-RS Service whose purpose was to mimic the behavior of the #RestController. I confirmed that the #BatchSize annotation does work in the application's deployment, at least, in JAX-RS Services! (NOTE: the service uses it own persistence.xml) ...
Test details (Updated 2020/07/30): What I did here was to create a new JAX-RS Service and deployed it inside the WAR application, next to the #RestController that presents the problem (I mean, it is the same WAR and the same physical JVM). Both services pull from database the same entity (same class - same classloader), which has a lazy Collection annotated with #BatchSize! ... If I invoke both services, the JAX-RS honors the #BatchSize and pulls the collection using the expected strategy, the #RestController does not ... So, what it is happening here? The only thing different between the services is that each one has a different persistence.xml: the persistence.xml for the JAX-RS is picked by Wildfly directly, the other one is picked by Spring and delegated to Wildfly (I guess) ...
I tried to add the properties: hibernate.batch_fetch_style (=dynamic) and hibernate.default_batch_fetch_size (=10), to the persistence.xml read by Spring ... No luck. I debug the Spring startup process and I saw that such properties are passed to the Spring Engine, but Spring does not care about them. The weird thing here is that properties like: hibernate.show_sql, Spring does honor them ... For those who are asking: "What does these properties do?" Well, they are global equivalent to apply #BatchSize to any JPA lazy collection or proxy without declaring such annotation in any entity.
I setup a small SpringBoot Project using the same Spring version as enterprise application (which is 1.5.8.RELEASE, by the way) and both the annotation and properties approach worked as supposed to.
I've been stuck with this issue for two days, any help to fix this will be appreciated ... thanks!
There are 2-3 possible issues that I can think off.
For some reason, whatever you modify isnt picked up by wildfly - Wildfly classpath resolution is a separate Topic and some missing configuration can cause you a nightmare. This you can identify if you have access to debug the query, and in if you put a breakpoint in the constructor of your Entity class, you will get a chance to evaluate the entity configuration being used, somewhere in the execution conetxt.
BatchSize doesnt work on OneToOne, It only works on OneToMany relationships.
A typical way to define BatchSize is to do along with Lazy load as mentioned in the example here. If you are not using Lazy fetch, hibernate assumes that you are willing to make an eager load and makes another select query to fetch all the details.Please confirm you are using the same syntax as given in the example above.
New Addition:
Put Conditional Breakpoints in PropertyBinder#setLazy() function, and may be backtrace it and put relavent breakpoints in CollectionBinder and AnnotationBinder. then restart/redeploy the server and see what data you are getting for the relavent properties. That will give you fair idea where it is failing..
Why conditional breakpoint? Its because you will have thousands of properties and if you do not add condition to the breakpoint, you will take 1 hour to reach your actual breakpoint
What should be the condition - If its property binder, the condition shoud be like `this.name == . For other classes also you can use the same approach.
Sorry for too detailed description on conditional breakpoints, you might find it redundent.
Looks like the only way to debug your problem is to debug hibernate framework from server startup, then only we will be able to find out the rootcause
I decided that i will split spring boot application into smaller pieces. One of those pieces was spring repository (models as entities). I decided that it will be done using autoconfiguration. so if i will attach that starter/dependency to project database with proper tables will be created automatically.
Before changes whole project was working fine.
So i moved my models to that new repository starter (They have entity annotation).
#Entity
#Getter
#Setter
public class Account implements Serializable {
I created spring.factories and placed it in proper place with proper values
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.application.RepositoryAutoconfiguration
The autoconfiguration class looks following:
#Configuration
#ComponentScan(basePackages = {"com.application.model"})
public class RepositoryAutoconfiguration {
}
I thought if i will do like that then entities will be created automatically in database.
So i attached that newly built depednecny to my main project and when i started that app i recievied:
Caused by: java.lang.IllegalArgumentException: Not a managed type: class com.application.model.Account
It looks like it is not working.
Do you have any hints how to handle that case ? I checked the stackoverlow and i could notice like in some cases the issue was connected with missing entity annotation, but it is not my case.
Thanks,
Jan
I'm trying to create project structure that would allow me to add/remove modules by simply having them on classpath. With #ComponentScan("com.companyname") annotation in my Spring Application it detects and creates annotated components from modules. But I get errors when trying to autowire my CrudRepository anywhere:
Field repo in com.companyname.somemodule.services.SomeService required a bean of type 'com.companyname.somemodule.repos.SomeRepo' that could not be found.
So I thought that maybe it somehow can't create repos if they are defined in one of modules, so I wen't ahead and added test repo to my base SpringApplication and to my surprise I got:
Field repo in com.companyname.modularapp.TestService required a bean of type 'com.companyname.modularapp.TestRepo' that could not be found.
Then I just removed my #ComponentScan annotation and suddenly TestRepo worked as I intended, I was able to persist and read Test entities normally. So apparently ComponentScan somehow either screw up creation of CrudRepository, or it's later detection.
I define my repos like this:
#Entity
public class Test {
#Id
private long id;
}
public interface TestRepo extends CrudRepository<Test, Long>{}
I'm trying out Spring Boot 2.0.0.M7 with this project but I doubt that's the cause.
Did I miss something?
Also you can define package for Repositories scan by :
#EnableJpaRepositories("com.companyname")
or in XML config
<jpa:repositories base-package="com.companyname"/>
If you are using spring-boot you might as well drop the #ComponentScan annotation, as there is one already defined in the #SpringBootApplication annotation. Maybe there's a conflict of some sort between them, it's hard to tell without looking at the code.
If you customizing package scans in your project, then probably you need to manually configure bean which requires path to scan, e.g. for JPA you can create your own bean of LocalContainerEntityManagerFactoryBean (you can find auto-configuration example here -
org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration#entityManagerFactory - class link from spring-boot 1.5.*).
But, if you do not require package scan customization, just put class annotated with #SpringBootApplication in project root, and pass it to spring::run method.
I'm currently working on a project with a plugin system using Java's ServiceLoader. The plugin manager creates an URL classloader with the URLs of the jar-files, which is used to load the plugins. When creating the EntityManagerFactory, I set the eclipselink.classloader property to the created URL class loader, which should enfore the EntityManagerFactory to use my classloader for entity autodetection. However, Eclipselink fails to detect the entities in the plugins.
Eclipselink's logging (log level set to finest) does not mention the entities in the plugins at all, only the entities in the base project. I even tried pre-loading the entity and metamodel classes, but still no change.
I have an application which connects to a zookeeper to perform operations on HBase. However, for Integration Tests, I have a class to create in-memory tables, and perform tests without trying to connect to said zookeeper.
I have defined a IntegrationTestAppConfig.class as follows:
#EnableAutoConfiguration(exclude = { AppConfig.class})
#ComponentScan
#Configuration
#EnableAsync
public class IntegrationTestAppConfig{
..... //this is where I create a bean for my HBaseConnectionManager to use my in-memory table environment
}
And, in my integration test class, I have the following:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = IntegrationTestAppConfig.class)
public class AHCLIManagerIT {
#Test
.....
}
Based on what I've read from the Spring-boot documentation, the integration test class should use IntegrationTestAppConfig.class for the application configuration.
However, when I run the Integration Test, I get an error saying connection to zookeeper timed out. In the stack trace, I see that the error occurred in AppConfig.java (my main class for app configuration), where it tries to create a HBaseConnection to the zookeeper.
I don't understand why my application is not using the App config class that I've defined in the annotations.
Is your AopConfig class actually an autoconfiguration class? Autoconfiguration classes are loaded by naming them in a spring.factories file in META-INF. The exclude attribute would only apply to those I believe. Auto configuration happens after regular app configuration anyways.
Also you have #ComponentScan on your config. If you really need to exclude AopConfig that would be the annotation I'd expect it to be on.
Though IMHO something doesn't seem right for doing a component scan in your tests