for example ,there are 2 beans.
parentClass is a generics class
// parentClass
#Service
public class ParentService<T> {
public ParentService(){
System.out.println("ParentService: class"+this.getClass()+" "+this);
}
}
//subClass
subClass extends parentClass and indicates that the generic is a "string" type
#Service
public class ChildService extends ParentService<String> {
public ChildService(){
System.out.println("ChildService: class"+this.getClass()+" "+this);
}
}
// TestCase
autowired the subClass , parentClass that generic is String
#RunWith(SpringRunner.class)
#SpringBootTest
public class OneBeanApplicationTests {
#Autowired
private ChildService childService;
#Autowired
private ParentService<String> stringParentService;
#Test
public void contextLoads() {
System.out.println(childService == stringParentService);// true
}
}
the answer is :TRUE
I am confused about that
=====================================
if i edit the test class
#Autowired
private ParentService parentService;
......
parentService==stringParentService; // false
this is the example project: https://github.com/AshameL/WhyIsSameBean
you can pull it and run the test class
I created one controller class and tried this
#Autowired
ParentService<String> stringParentService;
#Autowired
ChildService childService;
#Autowired
ParentService parentService; // Object class
#GetMapping("/test123")
public void contextLoads() {
System.out.println(childService.hashCode()+" : "+stringParentService.hashCode());
System.out.println(childService == stringParentService);
System.out.println(childService.equals(stringParentService));
System.out.println(Integer.toHexString(System.identityHashCode(childService)));
System.out.println(Integer.toHexString(System.identityHashCode(stringParentService)));
System.out.println("=====================");
System.out.println(parentService == stringParentService);
System.out.println(parentService.hashCode()+" : "+stringParentService.hashCode());
}
OUTPUT:
563182512 : 563182512
true
true
21917bb0
21917bb0
=====================
false
196061929 : 563182512
This is expected as when we have ParentService<String>, since hashcode is not overriden both Parent and Child class share same Object
In case of ParentService default type pass is Object thus different hashcode and so different Object.
Edit 1:
During Server Start up I can see following log
ParentService: classclass com.example.demo.service.ChildService com.example.demo.service.ChildService#2dc6b83f
ChildService: classclass com.example.demo.service.ChildService com.example.demo.service.ChildService#2dc6b83f
ParentService: classclass com.example.demo.service.ParentService com.example.demo.service.ParentService#349131e3
and when I do same with below code
public static void main(String[] args) {
ParentService parentService = new ChildService();
ParentService parentService1 = new ParentService();
}
OUTPUT:
ParentService: classclass com.example.demo.service.ChildService com.example.demo.service.ChildService#1d44bcfa
ChildService: classclass com.example.demo.service.ChildService com.example.demo.service.ChildService#1d44bcfa
ParentService: classclass com.example.demo.service.ParentService com.example.demo.service.ParentService#266474c2
which conclude that
#Autowired
ChildService childService;
#Autowired
ParentService<String> stringParentService;
are instance of ChildService class due to extend.
In java "==" compares object references.
Since ChildService extends from ParentService they essentially might have a reference to the same object in memory, hence you probably get true when comparing them using the "==" sign.
The default scope in Spring is singleton, so you will get the same instance of ChildService with autowiring.
Related
This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 7 months ago.
So I try to inject an interface implemention through a field. But can't figure it out why it's null.
Package
com.a
Interfacex
com.b
Interfaceximpl
Interfacex.java
public interface Interfacex {
void doA ();
}
Interfaceximpl.java
#Component
public class Interfaceximpl implements interfacex {
#Override
void doA(){
// do something
}
}
Main.java
public class Main {
#Autowired
Interfacex interfacex;
public static void main (String args[]){ //....}
}
This interfacex seems to be null.
#Configuration
#ComponentScan("com")
public class AppConfig { // nothing here}
There is no such setter injection in my case. I just inject the interfacex with #Autowired. Why is it null?.
Are you really placing the #Autowired on the field of the main class or its just an illustration? If you do - it won't work because the class on which #Autowired can happen must be by itself managed by Spring. And in this case its obviously not, because its a special class - an entry point of the application...
I suggest to use something like this instead:
#Component
public class EntryPoint {
#Autowired
Interfacex interfacex;
public void foo() {
// interfacex shouldn't be null
// because everything is managed by spring now
interfacex.doA();
}
}
public class Main {
public static void main(..) {
ApplicationContext ctx = ...
EntryPoint ep = ctx.getBean(EntryPoint.class);
ep.foo();
}
}
#Autowired annotation will not be recognized and acted upon by spring unless the class is a bean.
In this case, the 'Main' class is not a bean. So, #Autowired will do nothing.
You need to make 'Main' a bean. One way to do that is to add #Component annotation to that class.
Also, this seems like just something you are trying out to understand the working. In that case, you can try my above suggestion.
If you are doing this for prod, then you should change the class structure, class and variable names and the way you are creating beans.
I have a class with 2 static nested classes that do the same operation on 2 different generic types.
I exposed the 2 classes as beans and added #Autowired for the constructors as I usually do.
Here is the basic setup
abstract class <T> Parent implements MyInterface<T> {
private final Service service;
Parent(Service service){ this.service = service; }
#Override public final void doInterfaceThing(T thing){
T correctedT = map(thing);
service.doTheThing(correctedT);
}
protected abstract T map(T t);
#Service
public static class ImplA extends Parent<A> {
#Autowired ImplA (Service service){ super(service); }
A map(A a){ //map a }
}
#Service
public static class ImplB extends Parent<B> {
#Autowired ImplB (Service service){ super(service); }
B map(B b){ //map b }
}
}
And in another class I have
#Service
public class Doer {
private final List<MyInterface<A>> aImpls;
#Autowired public Doer(List<MyInterface<A>> aImpls){ this.aImpls = aImpls; }
public void doImportantThingWithA(A a){
aImpls.get(0).doInterfaceThing(a);
}
}
When I run the app, everything appears to be injected correctly and when I put a breakpoint in the ImplA and ImplB constructors, I have a not-null value for "service". I also have an ImplA bean in the aImpls list in Doer.
When I call doImportantThingWithA(a) however, "service" is null inside ImplA and I obviously die.
I'm not sure how this is possible because:
I see a nonnull value in my constructors for service which is a final field.
If spring is injecting ImplA and ImplB into another class, it should already have either injected a Service into ImplA or ImplB, or thrown an exception on bean initialization. I have nothing set to lazily load and all bean dependencies are required.
The reason for the nested classes is because the only thing that changes between the 2 implementations is the map() function. Trying to avoid extra classes for 1 line of varying code.
More info:
When I add a breakpoint in Parent.doInterfaceThing(), if I add a watch on "service" I get null as the value. If I add a getService() method, and then call getService() instead of referring directly to this.service, I get the correct bean for service. I don't know the implications of this but something seems weird with the proxying.
It looks like what is causing the issue is Parent.doInterfaceThing();
If I remove final from the method signature, "service" field is correctly populated and the code works as expected.
I don't understand at all why changing a method signature affects the injected value of final fields in my class... but it works now.
What I meant with my "use mappers" comment was something like this:
class MyInterfaceImpl implements MyInterface {
#Autowired
private final Service service;
#Override public final <T> void doInterfaceThing(T thing, UnaryOperator<T> mapper){
T correctedT = mapper.apply(thing);
service.doTheThing(correctedT);
}
// new interface to allow autowiring despite type erasure
public interface MapperA extends UnaryOperator<A> {
public A map(A toMap);
default A apply(A a){ map(a); }
}
#Component
static class AMapper implements MapperA {
public A map(A a) { // ... }
}
public interface MapperB extends UnaryOperator<B> {
public B map(B toMap);
default B apply(B b){ map(b); }
}
#Component
static class BMapper implements MapperB {
public B map(B a) { // ... }
}
}
This does have a few more lines than the original, but not much; however, you do have a better Separation of Concern. I do wonder how autowiring works in your code with the generics, it does look as if that might cause problems.
Your client would look like this:
#Service
public class Doer {
private final List<MapperA> aMappers;
private final MyInterface myInterface;
#Autowired public Doer(MyInterface if, List<MapperA> mappers){
this.myInterface = if;
this.aImpls = mappers; }
public void doImportantThingWithA(A a){
aMappers.stream().map(m -> m.map(a)).forEach(myInterface::doInterfaceThing);
}
}
I'm trying to unit test a camel route. The route under test extends a custom abstract RouteBuilder (I know about favouring composition over inheritance - this is maintenance code). I've set up my test as #Roman Vottner did over here. Everything works (is initialized) until I hit the first abstract class up the hierarchy. It has an #Autowired class which wasn't initialized (is null) even though it was mocked and #Autowired when the test started. Any ideas on how to solve my injection problem?
#RunWith(CamelSpringRunner.class)
#BootstrapWith(CamelTestContextBootstrapper.class)
#ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = {FooRouteTest.ContextConfig.class})
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class FooRouteTest {
#Configuration
#PropertySource({"classpath:some.properties", "classpath:environment.properties"})
public static class ContextConfig extends CamelConfiguration {
#Bean
public UserServices userServices() {
return mock(UserServices.class);
} //and many more of the like
}
#Autowired
private UserServices userServices; //and all the others too
#Test
public void testAfoo() throws Exception {
//....
template.setDefaultEndpointUri("direct://getTheData");
template.sendBody(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonNode));
//...
}
}
in the abstract super class while debugging:
#Autowired
public ClientServices clientServices;
//...
String clientNumber=clientServices.getLoggedInNumber(); //clientServices is null and not mocked!
//...
Solved this by explicitly declaring FooRoute as a bean:
#Bean
public FooRoute fooRoute(){
return new FooRoute();
}
#Override
public List<RouteBuilder> routes() {
final List<RouteBuilder> routes = new ArrayList<>();
routes.add(fooRoute());
return routes;
}
I have the following scenario in Spring :
public class ClassA{
#Autowired
private ClassB classB;
}
I'm using (Autowiring to be more precise) ClassA in my Test class. But what I'd like to do somehow is to modify ClassB just for my Junit, so with that, When ClassA is autowired in my test class, it loads the modified ClassB (instead of the original one).
Is there a way to achive that?
Can't think of another way to do this without Bean Configuration.
You can configure this in 2 ways:
First:
#Configuration
public class AppConfig {
#Bean
public ClassB classB() {
return new ClassB() {
// this is a subclass that inherits everything from ClassB, so override what you want here
}
}
}
Second: (taken from here)
#RunWith(SpringRunner.class)
#SpringBootTest
public class SomeTest {
// do this if you only want the modified classB in 1 place
#Configuration
static class TestConfig {
#Bean
public ClassB classB () {
return new ClassB() {
// same as the first
}
}
}
#Test
public void testMethod() {
// test
}
}
Finally, you could create a new interface ClassB and ClassBImpl in your main folder and ClassBTestImpl in your test folder. You still need to use one of the configuration.
In my spring-based project I have a core module ('core') with a class
#Component
public class Superclass {
// stuff
}
instances of which are injected by type throughout the code like this:
public class AService {
#Autowired
private Superclass superclass;
// service stuff
}
I also have two other modules that depend on the core module and one of which (let's call it 'module1') extends Superclass:
#component
public class Subclass extends Superclass {
// overridden stuff
}
The other module ('module2') uses Superclass as is.
Now I want that when I compile and run 'child1' an instance of Subclass is used everywhere an instance of Superclass is expected. So I write a configuration class:
#Configuration
public class Module2Configuration {
#Bean
public Superclass superclass(){
return new Subclass();
}
}
When I run this I see both Superclass and Subclass instantiated which is definitely not what I want. How do specify in 'module1' which type Spring should instantiate?
You can use #Qualifier("some name") annotation.
There is more information about that: http://blogs.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/
Spring eagerly instantiates singleton beans as stated in the documentation:
By default, ApplicationContext implementations eagerly create and configure all singleton beans as part of the initialization process.
which might explain why both #Components are created.
To specifiy which implementation is provided as a dependency you might want to check on Qualifiers that enable to choose between different implementations. In combination with lazy loading this should do the trick.
Depending on your personal taste you could also use delegation instead of inheritance using a separated interface:
public interface MyService {
public String foobar(int baz);
}
public static class CommonBehavior {
// whatever is used by Superclass and Subclass
}
#Component #Lazy
public class FormerSuperClass implements MyService {
private final CommonBehavior ...;
...
}
#Component #Lazy
public class FormerSubClass implements MyService {
private final CommonBehavior ...;
...
}
Good luck!
There are 2 methods: Use #Qualifier("SubclassName") Or Mark your subclass as #Component and declare the subclass when #Autowired
In your case:
Use #Qualifier("SubclassName")
#Component
public class Superclass {
// stuff
}
#component
public class Subclass extends Superclass {
// overridden stuff
}
public class AService {
#Autowired
#Qualifier("Subclass")
private Superclass superclass;
// service stuff
}
2.Mark your subclass as #Component and declare the subclass when #Autowired
public class Superclass {
// stuff
}
#component
public class Subclass extends Superclass {
// overridden stuff
}
public class AService {
#Autowired
private Subclass subclass;
// service stuff
}