I'm working on a system's back end that uses Spring Boot, REST, HATEOAS, Hibernate and PostgreSQL. For validation, I started using classes that extend org.springframework.validation.Validator. It works well, but only for calls made by the front end. For calls made in the back end, such as by using EntityManager, they don't fire. I've managed to have another validator being called in this situation by using #Constraint for ElementType.TYPE, but it only gets called for create and save methods.
Is it possible to use this validator to validate on delete methods too? There's a project here that's a non operational subset of the project I'm working on, containing the validators I mentioned.
Thanks in advance.
P.S.: I'd rather avoid manually calling the validators whenever I call a repository method in the back end.
P.P.S.: This answer makes me believe it's possible, but I couldn't translate the XML configuration to JavaConfig.
I finally found the answer. In application.properties, add:
spring.jpa.properties.javax.persistence.validation.group.pre-remove=javax.validation.groups.Default
The linked question told me which property I needed, but I didn't know where to place it. I tried to use custom Java configuration and even persistence.xml configuration, but several other things failed.
Here, I learned that "[...] all properties in spring.jpa.properties.* are passed through as normal JPA properties (with the prefix stripped) when the local EntityManagerFactory is created." So I just added that prefix and it worked.
Related
The Spring Boot documentation states that if you add your own DataSource bean, spring will not handle the Auto-configuration anymore.
Basically, I want to have two data sources in my project. I was thinking that I can explicitly config the second ds, and not annotate it with #Primary, and Spring will do the auto-config for the primary data source. After trying to do this without any success and reading the docs, it is still unclear to me what they really mean. Does declaring any bean of type DataSource stop the auto config, even if it's not the primary one? Or is the auto config stopped only if you annotate the bean with #Primary / leave it with the default name (which I believe is simply "dataSource"). I have manually configured the default data source so I know how to do that, but I want to know if it's really necessary.
Thanks, any help would be really appreciated, as I have been stuck on this one for a while now.
The documentation you linked to seems clear to me. Emphasise is mine.
Auto-configuration is non-invasive. At any point, you can start to define your own configuration to replace specific parts of the auto-configuration. For example, if you add your own DataSource bean, the default embedded database support backs away.
#Primary or the bean name is not mentioned at all, so I'm not sure why you would expect it to be relevant.
It even describes in the following paragraph how to run you application so you can see which autoconfigurations are applied and why (not).
If you need to find out what auto-configuration is currently being applied, and why, start your application with the --debug switch. Doing so enables debug logs for a selection of core loggers and logs a conditions report to the console.
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
Once I #EnableDataFlowServer my SpringBoot application, my own custom entities do not load. (I get the 'type not managed' exception which occurs when JPA isn't finding your entities).
These entities are found within another Spring module that I import, like
#Import({MyDomainsModule.class})
I'm using 2.0.0.m2 of Spring Cloud DataFlow.
Some debugging I've done:
If I add this to my Spring Boot application main class:
#EntityScan({
"com.company.mydomain.entities"
})
Then my entities start to load as usual, but then Spring DataFlow breaks. For example, any time I try to load the UI, I'll get:
|ne.jdbc.spi.SqlExceptionHelper| Table 'dataflow.appregistration' doesn't exist
That makes me thinking by simply adding the EntityScan, I broke some naming strategy since the actual name of the table is of course app_registration
I think this is mostly a 'how do I do multiple locations of JPA-based code in one project', rather than a Spring Cloud DataFlow question. But knowing the fix might require a better understanding of how SCDF. I've checked out the project and reading up both Spring Boot and how SCDF configures itself.
Any help is greatly appreciated!
I had a bad strategy coming in from one of my properties, overriding what SCDF added this to my application.properties.
So to be explicit, I set this in my properties:
spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
spring.jpa.hibernate.naming.implicit-strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
And then my SpringBoot application looks like
#SpringBootApplication(exclude = LocalDataFlowServerAutoConfiguration.class)
#Import({MyDomainModule.class})
#EnableDataFlowServer
// EnableDataFlowServer has an EntityScan, which causes ours to not be picked up!
// Look in DataFlowControllerAutoConfiguration for more information
#EntityScan({
"com.company.mydomain.entities"
})
I have a EntityListener that needs to be configurable (typical data source info: driver, user, password), but I´d like to avoid adding one more properties file to the project. Is there any way to retrieve from some standard configuration place such as web.xml? It seems that injection via #Resource will be only available in JPA 2.1 (I am using JPA 2.0).
UPDATE - to make this clear
In my entity bean, I have an annotation #EntityListeners(MyEntityListener.class). So MyEntityListener may have methods annotated with #PostPersist for example. When my entity bean is gonna be persisted, this method is called. What I want is to retrieve the data for MyEntityListener initialization without using another configuration file.
http://openjpa.apache.org/builds/2.2.1/apidocs/org/apache/openjpa/audit/Auditor.html does the trick. It works (my bad, it was a misconfiguration of mine). Actually it works pretty well.
<property name="openjpa.Auditor" value="com.acme.Auditor(param2=10,param2='hello')"/>
We are starting a new project using Spring MVC, and we would like to move away from annotation-driven request/url mapping. We wish to implement the following use case:
Use Case A
User enters a URL.
The request mapping handler retrieves a list of mappings (e.g. from the DB), and based on this dynamic list of mappings, it calls the relevant controller.
This is because we want to be able to do the following as well:
Use Case B
We want to load a new Controller (perhaps a new reports module) into the web app without having to redeploy or do a server restart.
We will map this new Controller to a URL and persist it somewhere (most likely the DB).
We would like the Controller to be registered in the Spring app context (managed by Spring).
We would then like to use this new Controller in the request mapping.
We've taken an initial look at the different ways we can implement this, but we are unsure of the best architecture/method to go about this route. A couple of questions:
For Use Case A, how do we implement this within the Spring MVC framework (or if it's possible)?
For Use Case B, is there a good framework or way to be able to do dynamically loading and registering of this for web applications? We've taken a cursory look at OSGI but it seems to be advisable for use in non-web applications.
For Use case A :
Instead of DB you can keep the url mappings in a property file and then use property place holder to initialize beans using xml configuration on context up. This way remaining inside the spring framework, you can avoid annotations.
For Use Case B :
Tomcat supports dynamic reloading of classes but that to of only non structural changes in class file. But this has memory leaks as well as it doesnt cleans up old instance of class loader rather it creates a new instance.
Its quite achievable using spring-mvc-router API.
Please check below link
url-action mapping & routing in Spring MVC 3.0
Here the URL can be configured to controller.method using .conf file, but this can be achievable using java configuration, and i haven't tried so far.
Also if xml configuration chosen, then check out the property 'autoReloadEnabled', but its not adviceable for production use.
Hope this helps!!!