hot deploy changes done to beans in application context dont show up - spring

In the process of extending functionality of my application, I added injected few additional bean references into my existing bean definitions in applicationContext. I included their getters and setters in my java class. Class A refers to beans B and C newly now and in class A, I added getters and setter for B and C and used these getters in methods inside Class A.
Beans B and C are nothing more than Maps and there is a class D in which I put values into these beans.
Now, instead of generating a whole war file again in the production machine, I generated the war in my local copy. From this war I picked up classes A and D and replaced the ones on production machine with these new classes. Also, I replaced the applicationContext.xml.
After restarting tomcat on the production machine, I get a NPE in Class A which is because of the getter of bean B. My values dont seem to be injected in the bean.
What can I do to solve this? I do not want to redeploy the whole war on my production machine.

If you restart tomcat it will unpack any war file that is present, overwriting any changes you have done manually. If I understand correctly you are attempting to copy class files into your exploded war. Not a particularly good idea.
You don't have to gerenate a war file on the same machine it is deployed on (in fact that would be unusual). You may app specific settings to be aware of.

Related

Does ComponentScan order matter?

I'm setting up a very small Spring/REST/JPA project with Boot, using annotations.
I'm getting some Bean not found errors in my REST controller class that has an Autowired repository variable, when I move my JPA repository class out to a different package, and calling componentscan on its package. However, everything was working fine when all my files(5 total) were in the same package.
So I was wondering, however unlikely, if the component scan order matters? For example, if a class is AutoWiring some beans from a package that has not been 'component scanned' yet, will that cause a Bean not found error?
No, Spring loads all configuration information, from files and annotations and the environment when appropriate. It then creates beans (instances of classes) according to a dependency tree that it calculates in memory. In order to do this it has to have a good idea of the entire configuration at startup. The whole model derived from all the aggregated configuration information is called the Application Context.
In modern versions of spring the application context is flexible at runtime and so it's not quite the case that all the configuration is necessarily known up front, but the configuration that is flexible is limited in scope and must be planned for carefully.
Maybe you need to share some code. When you move that stuff, you also need to tell Spring where they went. My guess would be you haven't defined #EntityScan and #EnableJpaRepositories (which default to the location of #EnableAutoConfiguration).
There could be several problems:
You moved your class out of the some package where you have #ComponentScan without arguments. That basically means that components are scan only in this package and its children. Thus, moved class are not scanned and there is no bean to wire.
Wrong package name in #ComponentScan args.
The order isn't matter at all. There is an #Order annotation, but it's purpose is more about loading multiple implementations of sth in a different order.
At first Bean Definitions are created and they have nothing to do with wiring. Then via bean post processors, autowired beans are injected. Since there were no bean definition. There is nothing to inject.
In a well structured program it doesn't, because first each bean gets instantiated, then autowired and then you can actually use them.
However there could be situations where the order does matter and I had an issue figuring out what was going on. So this is an example where it would matter:
You have some Repository that you want to fill with data initially, call it SetupData component.
Then you use #PostConstruct to save the default objects.
You have some component that this Repository depends on but isn't managed by Spring, for example a #Converter.
And that #Converter depends on some other component which you would statically inject.
In this case #PostConstruct methods will be executed before the components into your #Converter get autowired which will result in an exception.
Relying on ComponentScan order is a bad habit, because it's not intuitive especially when you are working with multiple people who may not know about. Or there might be such dependencies that you can't fix the code by changing the scan order.
The best solution in this case was using a task executor service that takes care of running initialization functions.

Spring autowire stops working for classes on the Tomcat classpath

Inside my library FooLibrary.jar Spring instantiates class com.example.FooImpl which has a property bars. I have lots of Bar instances also instantiated by Spring. A set of bars is autowired into FooImpl like this:
#Component
public class FooImpl {
#Inject
private Set<Bar> bars;
In a standalone application, Spring instantiates the Bar instances, instantiates the FooImpl instances, and then autowires FooImpl.bars with the set of Bars. It works.
Now I'm running the same Spring configuration in a webapp inside Tomcat. FooLibrary.jar is inside WEB-INF/lib, and everything continues to work as outlined above.
The problem is that the web app automatically compiles somes classes using JavaCompiler, which can't find its dependencies for dynamically compiling unless I place that library on the startup Tomcat path. The minute I add FooLibrary.jar to the Tomcat classpath (e.g. in in the launch configuration of Tomcat inside Eclipse, or I presume startup.sh or setclasspath.bat if running Tomcat standalone), autowire stops working.
That is, when my webapp starts up, Spring creates all the Bar instances, then instantiates FooImpl, but never autowires the set of Bars into FooImpl.bars. Any idea why?
(Does it have something to do with the Spring ContextLoaderListener being started from the webapp classloader, but the FooImpl and Bar instances coming from the Tomcat classloader, I wonder?)
Autowiring can fail due to incompatible types (e.g. classes loaded in multiple classloaders).
Since you already place the JAR in tomcat's boot classpath, it must be visible to the webapp as well without you having to place the JAR in WEB-INF/lib.
You can make the dependency scope provided to not have Maven place it in WEB-INF/lib.

JEE6 : Alternative EJB declaration

I'm using JBoss 7.1.1 with CDI.
I've got a Stateless bean named ServiceAccount in JNDI. This is the real service implementation.
I've got another Statelss bean named ServiceAccountMock which is a Mock service.
The both herited from the same interface and are packaged in a service.ear.
What I want to do is to declare the mock service as alternative in bean.xml, redeploy my services ear, and then all the client see the mock version (without changing anything on client side).
When I deploy my service.ear, JBoss says :
java.lang.IllegalArgumentException: JBAS011046: A component named 'ServiceAccount' is already defined in this module
This is true, both services are declared the same way (#Stateless(name="ServiceAccount")).
If I change the name of the mock version, I have to change on client side which EJB is used (and I don't want to do that).
Does anyone know how to do that ?
I don't think you will be able to deploy 2 beans with the same name in the same application.
If the clients of the bean are only local, you should use CDI type injection selection.
Remove the name of the beans or put different name if you realy need a name (The mock will have a different name that the real implementation).
Keep the #Alternative annotation on the mock.
At the injection point, use the interface as the type of variable (and probably using the #Inject annotation instead of the #EJB one may help).
The EJB specification and CDI aren't yet completly aligned. EJB has some element like the name that need to be unique over the application and is not taken into account in the CDI alternative functionaltity.
So I don't think you will be able to mix EJB name injection selection and CDI alternative injection selection.
First you need to annotate ServiceAccountMock with #Alternative, to tell the container not to use it if not instructed to.
#Stateless(name="ServiceAccount")
#Alternative
public class ServiceAccountMock{
....
}
Then in beans.xml you need to tell the A/S to pick the mock implementation:
...
<alternatives>
<class>xx.yy.ServiceAccountMock</class>
</alternatives>
...

Annotation-specified bean name conflicts with existing, non-compatible bean def

I'm having a problem with some Spring bean definitions. I have a couple of context xml files that are being loaded by my main() method, and both of them contain almost exclusively a context:component-scan tag. When my main method starts up, I get this error from Spring:
Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'converterDAO' for bean class [my.package.InMemoryConverterDaoImpl] conflicts with existing, non-compatible bean definition of same name and class [my.other.package.StaticConverterDAOImpl]
Both DAO classes are annotated this way:
#Repository("converterDAO")
public class StaticConverterDAOImpl implements ConverterDAO {
...
}
The in-memory dao also has the #Repository("converterDAO") annotation. The dao is referenced in other classes like this:
...
private #Autowired #Qualifier("converterDAO") ConverterDAO converterDAO;
...
I want one DAO to override the definition of the other one, which as I always understood it was one of the principal reasons to use a DI framework in the first place. I've been doing this with xml definitions for years and never had any problems. But not so with component scans and annotated bean definitions? And what does Spring mean when it says they are not "compatible"? They implement the same interface, and they are autowired into fields that are of that interface type. Why the heck are they not compatible?
Can someone provide me with a way for one annotated, component-scanned bean to override another?
I had a similar issue with Spring 4.x using #RestController. Two different packages had a class with the same name...
package com.x.catalog
#RestController
public class TextureController {
...
package com.x.cms
#RestController
public class TextureController {
...
The fix was easy...
package com.x.catalog
#RestController("CatalogTextureController")
public class TextureController {
...
package com.x.cms
#RestController("CMSTextureController")
public class TextureController {
...
The problem seems to be that the annotation gets autowired and takes the class name by default. Giving it an explicit name in the #RestController annotation allows you to keep the class names.
In an XML file, there is a sequence of declarations, and you may override a previous definition with a newer one. When you use annotations, there is no notion of before or after. All the beans are at the same level. You defined two beans with the same name, and Spring doesn't know which one it should choose.
Give them a different name (staticConverterDAO, inMemoryConverterDAO for example), create an alias in the Spring XML file (theConverterDAO for example), and use this alias when injecting the converter:
#Autowired #Qualifier("theConverterDAO")
I had a similar problem, with two jar libraries (app1 and app2) in one project. The bean "BeanName" is defined in app1 and is extended in app2 and the bean redefined with the same name.
In app1:
package com.foo.app1.pkg1;
#Component("BeanName")
public class Class1 { ... }
In app2:
package com.foo.app2.pkg2;
#Component("BeanName")
public class Class2 extends Class1 { ... }
This causes the ConflictingBeanDefinitionException exception in the loading of the applicationContext due to the same component bean name.
To solve this problem, in the Spring configuration file applicationContext.xml:
<context:component-scan base-package="com.foo.app2.pkg2"/>
<context:component-scan base-package="com.foo.app1.pkg1">
<context:exclude-filter type="assignable" expression="com.foo.app1.pkg1.Class1"/>
</context:component-scan>
So the Class1 is excluded to be automatically component-scanned and assigned to a bean, avoiding the name conflict.
I had a similar problem, and it was because one of my beans had been moved to another directory recently. I needed to do a "build clean" by deleting the build/classes/java directory and the problem went away. (The error message had the two different file paths conflicting with each other, although I knew one should not actually exist anymore.)
Sometimes the problem occurs if you have moved your classes around and it refers to old classes, even if they don't exist.
In this case, just do this :
mvn eclipse:clean
mvn eclipse:eclipse
This worked well for me.
I had the same issue. I solved it by using the following steps(Editor: IntelliJ):
View -> Tool Windows -> Maven Project. Opens your projects in a
sub-window.
Click on the arrow next to your project.
Click on the lifecycle.
Click on clean.
I also had a similar problem. I built the project again and the issue was resolved.
The reason is, there are already defined sequences for the Annotation-specified bean names, in a file. When we do a change on that bean name and try to run the application Spring cannot identify which one to pick. That is why it shows this error.
In my case, I removed the previous bean class from the project and added the same bean name to a new bean class. So Spring has the previous definition for the removed bean class in a file and that conflicts with the newly added class while compiling. So if you do a 'build clean', previous definitions for bean classes will be removed and compilation will success.
If none of the other answers fix your problem and it started occurring after change any configuration direct or indirectly (via git pull / merge / rebase) and your project is a Maven project:
mvn clean
Explanation internal working on this error
You are getting this error because after instantiation the container is trying to assign same object to both classes as class name is same irrespective of different packages......thats why error says non compatible bean definition of same name ..
Actually how it works internally is--->>>>.
pkg test1;
….
#RestController
class Test{}
pkg test2;
….
#RestController
class Test{}
First container will get class Test and #RestController indicates it to instantiate as…test = new Test(); and it won’t instantiate twice
After instantiating container will provide a reference variable test(same as class name) to both the classes and while it provide test reference
To second class it gets non compatible bean definition of same name ……
Solution—>>>>
Assign a refrence name to both rest controller so that container won’t instantiate with default name and instantiate saperately for both classes irrespective
Of same name
For example——>>>
pkg test1;
….
#RestController(“test1”)
class Test{}
pkg test2;
….
#RestController(“test2”)
class Test{}
Note:The same will work with #Controller,#Service,#Repository etc..
Note: if you are creating reference variable at class level then you can also annotate it with #Qualifier("specific refrence name") for example
#Autowired #Qualifier("test1")
Test test;
I had the same issue on IntelliJ after moving an existing file to a new package, solved cleaning caché, when trying to run with maven got that error. I managed solve it with:
cache:clean
Using Eclipse, I had moved classes into new packages, and was getting this error. What worked for me was doing:
Project > Clean
and also cleaning my TomCat server by right-clicking on it and selecting clean
Scenario:
I am working on a multi-module Gradle project.
Modules are:
- core,
- service,
- geo,
- report,
- util and
- some other modules.
So primarily we have prepared a Component[locationRecommendHttpClientBuilder] in geo module.
Java Code:
import org.springframework.stereotype.Component
#Component("locationRecommendHttpClientBuilder")
class LocationRecommendHttpClientBuilder extends PanaromaHttpClientBuilder {
#Override
PanaromaHttpClient buildFromConfiguration() {
this.setURL(PanaromaConf.getInstance().getString("locationrecommend.url"))
this.setMethod(PanaromaConf.getInstance().getString("locationrecommend.method"))
this.setProxyHost(PanaromaConf.getInstance().getString("locationrecommend.proxy.host"))
this.setProxyPort(PanaromaConf.getInstance().getInt("locationrecommend.proxy.port", 0))
return super.build()
}
}
application-context.xml
<bean id="locationRecommendHttpClient"
class="au.co.google.panaroma.platform.logic.impl.PanaromaHttpClient"
scope="singleton" factory-bean="locationRecommendHttpClientBuilder"
factory-method="buildFromConfiguration" />
Then it is decided to add this component in core module.
One engineer has previous code for geo module and then he has taken the latest module of core but he forgot to take the latest geo module.
So the component[locationRecommendHttpClientBuilder] is double times in his project and he was getting the following error.
Caused by:
org.springframework.context.annotation.ConflictingBeanDefinitionException:
Annotation-specified bean name 'LocationRecommendHttpClientBuilder'
for bean class
[au.co.google.app.locationrecommendation.builder.LocationRecommendHttpClientBuilder]
conflicts with existing, non-compatible bean definition of same name
and class
[au.co.google.panaroma.platform.logic.impl.locationRecommendHttpClientBuilder]
Solution Procedure:
After removal the component from geo module, component[locationRecommendHttpClientBuilder] is only available in core module. So there is no conflicting situation. Issue is solved by this way.
I faced this issue when I imported a two project in the workspace. It created a different jar somehow so we can delete the jars and the class files and build the project again to get the dependencies right.
In my case, issue was with pom.xml
I had dependency added in my application pom.xml for two different packages, which were reflecting to same class name.
Check your pom.xml or annotations which can be the possible injection point for same class.
if you build server with file jar and you use mvn clean install then you change branch with git you have to use command mvn clean either it throw exception as on the article.
key word: mvn clean
Refresh gradle project on Eclipse solved this problem for me

Calling remote EJB3 without interface classes available

When calling remote EJB3 (Glassfish) from another EJB module, it is usual to have interfaces available, they are included as JAR file so that when you do JNDI lookup everything works as expected.
I have a situation where EJB3 JNDI name is determined at runtime, and my attempts to access the EJBs retrieved from JNDI in usual way fail, container complains ClassNotFound for remote interface classes. This is odd to me, since all the interface classes extend a parent interface for which I DO have a dependency in my calling EJB module, i.e.:
IParent ejbRef = (IParent) JndiLocator.getObject("jndinameRemote");
Is this possible with EJB3, without the need to have an exact remote EJB interface bytecode available in my JAR?
Bozo
Even though i am exactly not sure what the above setup is , I had a similar need of trying to invoke EJB when the client jars are not known during the compile time, infact in addition there is also no way for me to know what Application service is the EJB deployed at.
I had managed to do this by writing my Customized Class Loader , the catch here is that the Class which in turn tries to invoke the EJB must be itself loaded using the Customized class loader along with all the necessary jars i.e client jar with interfaces and models and the application server specific client jar.
I passed all the context properties as an input to my Invoker class to initialize context factory and invoke the bean.
These are high level steps to achieve this
Create Class EJBInvoker with method invokeEJB, you can pass it couple of Maps with properties for preparing context and Ejb interface , method , parameters classes , values and output class.
Use reflection to create instance of InitialContextFactory as well as Bean object , parameters and method invokation.
Add the above class to separate jar file and invoke the method with properties required from external project using a customized class loader.

Resources