Spring circular dependency issue root cause - spring

I am having circular dependency in my application. I did not get any circular dependency issue while server startup on my local setup or other 3 setups I was working on.
But, I was getting circular dependency error on server startup on production environment.
Below was the error :
Error creating bean with name 'someBean': Bean with name 'someBean' has been injected into other beans [someOtherBean] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.
when I added default-lazy-init = "true" in my application_context.xml file, error got resolved.
My question is, how come I wasn't getting any such error on my local or other setup even though I wasn't having default-lazy-init = "true" in my application_context.xml file. I came to know that the problem can be solved in several ways. But I would like to know the root cause of how spring differs in bean creation from one system to another. Or is it specific to OS or Tomcat server.

Related

Flyway migration error details with Spring Boot

We have a project using Spring Boot and flyway.
When we run a migration that fails, with logs levels all set to DEBUG, we only got these messages:
[DEBUG] org.flywaydb.core.internal.command.DbValidate - Validating migrations ...
[DEBUG] org.flywaydb.core.internal.scanner.Scanner - Filtering out resource: db/migration/V1/V1_202103081030__account.sql (filename: V1_202103081030__account.sql)
[DEBUG] org.flywaydb.core.internal.scanner.Scanner - Filtering out resource: db/migration/V1/V1_202103081040__place.sql (filename: V1_202103081040__place.sql)
[DEBUG] org.flywaydb.core.internal.scanner.Scanner - Filtering out resource: db/migration/V1/V1_202103151608__document.sql (filename: V1_202103151608__document.sql)
[DEBUG] org.flywaydb.core.Flyway - Memory usage: 147 of 254M
[ERROR] org.springframework.boot.web.embedded.tomcat.TomcatStarter - Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'webSecurityConfig': Unsatisfied dependency expressed through method 'setContentNegotationStrategy' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration': Unsatisfied dependency expressed through method 'setConfigurers' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'openEntityManagerInViewInterceptorConfigurer' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration$JpaWebConfiguration.class]: Unsatisfied dependency expressed through method 'openEntityManagerInViewInterceptorConfigurer' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'openEntityManagerInViewInterceptor' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration$JpaWebConfiguration.class]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.api.exception.FlywayValidateException: Validate failed: Migrations have failed validation
...
[INFO ] org.apache.catalina.core.StandardService - Stopping service [Tomcat]
...
Caused by: org.flywaydb.core.api.exception.FlywayValidateException: Validate failed: Migrations have failed validation
There is no more details about the reason of the failure (a failing query, an unmatched checksum, ...).
I look at the spring.flyway application properties but found nothing that could be of any help here.
What should we do to display the flyway root error in our logs at server startup?
EDIT: To be clear, the problem is not the failure itself (setting a breakpoint in Flyway classes can reveal the source error). The problem is the missing error details in the logs.
I was having the same problem and found that it was related to the Flyway version I was on (Spring Boot 2.4.3, which uses Flyway 7.1.1). It's a known issue 2987 - Display all validate messages in exceptions, fixed in Flyway 7.2.0.
They recommend running flyway validate -outputType=json as a workaround to get a detailed error message. I tried that, but still didn't get a detailed error message.
The solution that worked for me was upgrading to Flyway 7.2.0, by specifying the version in my pom file:
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>7.2.0</version>
</dependency>
I don't know specifically what is failing, but this might help point you in the right direction.
Open up DbValidate (flyway class). (Download sources if you need to)
Put a break point in the else statement on lines 186-187
Start server again
That will at least tell you which file is failing.
You then might be able to make an enhancement request to the Flyway project for better error reporting.
Well, a lot of things can happen, but one possible reason is that you've changed the migration file after you've applied it already. I'll explain by use case:
Let's say that at time X you have 2 migrations (technically implemented in SQL files): A1 and A2.
This is your first commit with A1 and A2 and when you run the application, flyway creates a special table in the database to see which migrations were already applied. Obviously, there are no migrations there yet at time X so it creates a table, applies A1 and A2, and adds 2 records in the table. These records among other things should include a checksum. Simply put you can think about these checksum as a hash (like sha1) of the content of A1 and A2 correspondingly.
So far so good, now fast forward in time (to time Y) when you introduce a new migration file A3.
When you re-deploy the application, flyway checks that A1 and A2 that have already been applied have not changed, and only after that it applies the new migration.
Now, this validation is really a prerequisite to applying migration A3 checks these hashes - checksums. This is reasonable - because if you happen to have changed A1 or A2 - what should the flyway do - how it can guarantee that migrations work as expected?
You can read also in the official flyway documentation about this validation, however, you get the idea I believe. Someone has changed the checksum by changing one of your existing migrations and have tried to redeploy the applications.
Simply put, Once the migration file has been applied - it can't be changed in a source tree
Now the scenario that I've described is one possible scenario, in general, you don't really have to even create migration A3, it is enough to change the existing migration and try to re-run the application - the validation will fail.

JHipster Spring Boot where is package name used ComponentFind set?

How do I adjust package name in #ComponentFind for JHipster? I renamed some packages and now I am getting error that it does not find any bean CustomAuditEventRepository required a bean of type 'com.mynewpackagename.repository.PersistenceAuditEventRepository' that could not be found. Consider defining one. Well there never was a Bean defined for this so I assume its a problem with package name scanned by #ComponentFind but I cannot see exactly where to set this it seems like its in config but I am not sure exactly where to set this. Doing a search I dont see a packageName set to new or old value.
I tried changing package name in .yo-rc.json
"packageName": "com.mycompany.newpackagename",
"packageFolder": "com/mycompany/newpackagename",
But that does not seem to solve the issue. Where do I check if this bean was generated or not. How do I kick off bean generaton? I am running with ./mvnw

Storing non-serializable bean SpringViewDisplayRegistrationBean

I'm playing around with Vaadin and Spring Boot, but at the moment I always see the following log output with every reload:
Storing non-serializable bean [com.vaadin.spring.internal.SpringViewDisplayRegistrationBean#561f1569] with name [com.vaadin.spring.internal.SpringViewDisplayRegistrationBean#0] in [UIBeanStore[id=225748b3, name=UI:0]]
I don't have any idea where to search, which class or which part of the code could cause that. Any idea where to start?

Spring - usage of alias vs names

I am confused on the usage of alias. I do understand what alias is and how it is being used but i don't see how it can be any different than using names on a bean definition.
<bean id="xyx" name="abc,def" .. />
<alias name="xyx" alias="pqr"/>
Why the alias when i can use abc or def?
In my mind bean aliasing can be helpful in large system, where you can not manipulate bean names. You have option to create your own name (alias) specific for your part of the system...
from Spring documentation (3.0.x)
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/
...it is sometimes desirable to give a single bean multiple names,
otherwise known as bean aliasing...
therefore creating multiple names or/and aliasing are the same thing.
A use case maybe when you want to customize some beans that are already defined somewhere in a modular application (each module is a spring project for example), the bean maybe defined by a third-party framework/API or even your team. In that case you want that only inside your spring project call the customized version without altering other modules (projects), to do that just add the alias in your spring configuration which is indeed a powerful feature:
<alias alias="globalBeanService" name="customizedBeanService" />
Hence, whenever spring find a call to the globalBeanService, it will inject customizedBeanService for you inside your specific module.
Without this feature, you should go through all classes and modify the bean manually!!
An aliased bean will always have higher priority over a non-aliased one, and in case of having different beans with the same alias then the last one declared will have the priority. In other words, the aliased bean will override the non-aliased beans.
This can be particularly useful when creating big projects or when you are building extensions to your project and don't want to touch the original bean definition.
Alias has a specific using scenario which multiple names don't have:
Imagine multiple config xml files in your project, most of which are authored by your colleagues, and you need to add your own config.xml file. Using you'll be able to refer to a bean defined in another config file with a different name that's maybe more meaningful to your config, without having to touch your colleagues' config files.
I recently found another use case where alias easily solved a problem.
When auto configuration is active, Spring Boot provides the bean serverProperties which can be used to access information about the server currently running the web app.
In integration tests (i.e. when #SpringBootTest annotation is present) the same bean is available under the name org.springframework.boot.autoconfigure.web.ServerProperties.
Of course it is possible to use a different profile for integration testing, but that would require manual change of configuration at multiple places. However, simply by adding
<alias name="serverProperties" alias="org.springframework.boot.autoconfigure.web.ServerProperties"/>
the same configuration files can be used for integration tests and in production.
This might be a bug in Spring Boot, however alias easily solve the problem without waiting for a new release. And most certainly I have no possibility to alter the Boot configuration myself.

XSLT ClassCastException in WebSphere when Spring tries to create an AnnotationMethodHandlerAdapter

When starting WebSphere, I get this exception:
Could not instantiate bean class [org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter]:
Constructor threw exception; nested exception is java.lang.ClassCastException:
com.ibm.xtq.xslt.jaxp.compiler.TransformerFactoryImpl incompatible with
javax.xml.transform.TransformerFactory
Caused by: java.lang.ClassCastException: com.ibm.xtq.xslt.jaxp.compiler.TransformerFactoryImpl
incompatible with javax.xml.transform.TransformerFactory
at javax.xml.transform.TransformerFactory.newInstance(Unknown Source)
at org.springframework.http.converter.xml.AbstractXmlHttpMessageConverter.<init>(AbstractXmlHttpMessageConverter.java:47)
at org.springframework.http.converter.xml.SourceHttpMessageConverter.<init>(SourceHttpMessageConverter.java:45)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.<init>(AnnotationMethodHandlerAdapter.java:197)
This doesn't seem have any impact on any beans in my applicationContext.xml but it's still odd. For me, this looks as if IBM classes are leaking into my application.
How can I fix this? I already set the option "Access to internal server classes" to "Restrict".
It was indeed a class-loading issue, however this cannot be solved by changing class-loader settings.
The problem was that the xml-apis and javax.xml jars were being imported over some maven dependencies.
Since we already set the class loader policies for the application to PARENT_LAST, the javax.xml.transform.TransformerFactory was being loaded from the WebApp-Class loader from our jar files.
However its implementation 'com.ibm.xtq.xslt.jaxp.compiler.TransformerFactoryImpl' was coming from the server class loader, this one was linked to the javax.xml.transform.TransformerFactory provided by the JDK/JRE.
Since the classes were loaded from different sources a ClassCastException was thrown.
Removing all dependencies to xml-apis / xerces / javax.xml jars solved the problem.
Since these APIs are now part of the JDK they no longer need to be imported.
... and if you wonder why I know so much about this issue: I work together with Aaron. ;)
I can't speak for Restrict as I have no personal experience with it,But I think the problem is more to do with IBM Class Loader. The class you are referring to is part of IBM Java implementation of TransformerFactory, I think you can try one of the following to solve this issue on hand
Either change the server class loader policy to PARENT_LAST (This way class loader will find the class from application's local class path, before going to up the chain all the way to java run time)
The other option would be look at the jaxp.properties file, I think it is located in (was_root\java\jre\lib), I only read about this option never actually used it
Why do you say IBM classes are leaking into your application?
The TransformerFactory is asked to create a newInstance. It follows a sequence of steps to determine which TransformerFactory to use. If none of the config is specified, it simply chooses to use the default factory.
Here is the javadoc for TransformerFactory:
http://download.oracle.com/javase/1.5.0/docs/api/javax/xml/transform/TransformerFactory.html#newInstance()
What is the OS ? Is that AIX?
http://www.ibm.com/developerworks/java/jdk/aix/j664/sdkguide.aix64.html
Looking at this doc (link above) for AIX it tells me that this is the default Impl:
javax.xml.transform.TransformerFactory
Selects the XSLT processor. Possible values are:
com.ibm.xtq.xslt.jaxp.compiler.TransformerFactoryImpl
Use the XL TXE-J compiler. This value is the default.
Post back additional information so that we can try and troubleshoot this.
HTH
Manglu

Resources