2

I'm still learning spring dependency injection in depth.

My first class is a configuration class, where i declare to the container to load and manage the beans declared in the annotated methods.

package ioc.question_004;

import ioc.commun.Person;
import ioc.commun.Profession;
import org.springframework.context.annotation.*;

@Configuration
public class MyConfiguration {

    @Bean
    public Profession profession(){
        return Profession.builder()
                     .name("professor")
                     .description("professor in the university")
                     .build();
    }

    @Bean
    public Person person(){
        return Person.builder()
                     .name("Bagna")
                     .age(52)
                     .profession(profession())
                     .build();
    }

}

My second class is a daoRepository, it looks likes:

package ioc.question_008.dao;

import ioc.commun.Person;
import lombok.*;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;

@Repository
@Builder
@Setter
@Getter
@EqualsAndHashCode
@ToString
public class MyDaoRepository implements dao {

    List<Person> personList = new ArrayList<>();

    @Override
    public boolean save( Person person ){
        return this.personList.add(person);
    }

    @Override
    public boolean delete( Person person ){
        return  this.personList.remove(person);
    }

}

My running code is as follows:

@Configuration
@Import(MyConfiguration.class)
@ComponentScan(basePackageClasses = {MyDaoRepository.class} )
public class DependencyInjection {
    public static void main( String[] args ) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DependencyInjection.class);
        dao myDaoRepository = (MyDaoRepository) context.getBean("myDaoRepository");
        System.out.println(myDaoRepository);
    }

}

Magically MyDaoRepository contains the @Bean person declared in the configuration class MyConfiguration:

MyDaoRepository(personList=[Person(name=Bagna, age=52, profession=Profession(name=professor, description=professor in the university))])

I thnik that the container injected this object automatically even if i didn't ask for that. May be some @Autowired annotation is added by the compiler. I'm not sure.

Could you please explain to me how i can ask the spring container to not inject the beans even if they exists in the container(the bean person for example), unless i ask the to do the injection by myself with the @Autowired annotation.

sfiss
  • 2,119
  • 13
  • 19
xmen-5
  • 1,806
  • 1
  • 23
  • 44
  • 1
    What do you mean "contains" it? The list in the repository? – daniu Jul 03 '19 at 17:50
  • yes, automatically the list contains this person object declared in the configuration class.. – xmen-5 Jul 03 '19 at 17:52
  • 4
    You can't ask Spring not to inject bean dependencies if you *also* tell Spring (via component scanning) to automatically create the beans itself. If you want manual control, don't component-scan and write an `@Bean` method yourself. – chrylis -cautiouslyoptimistic- Jul 03 '19 at 18:13
  • May be i wasn't clear and explicit in my question. 1- The solution i was willing is to ask for dependency injection but not using the bean of type person defined in the configuration class.(knowing that including this configuration class is manadatory for others bean instance and the solution to remove @Import will not work.) 2-returning to my code, how was the person object injected to my list(injection by constructor, setter method or field injection)? – xmen-5 Jul 03 '19 at 18:51

1 Answers1

7

The reason is the combination of spring's autowiring of collections and lombok's Builder

First, the @Builder adds an all args constructor MyDaoRepository(List<Person> list).

Second, spring automatically detects your factory methods @Bean public Person person().

Now, since the constructor expects a collection, spring accumulates all Person-beans it can find into a List and injects it into the constructor, setting the list accordingly.

I think (but it is currently untested but documented here), that adding @Autowired(required = false) to your List<Person> persons property is what you want in this case, as that marks it as optional and spring will not inject it. (EDIT: I was mistaken, you still need the no-args-constructor for this to work, but without any @Autowired annotation the list would not get injected that way anyway. The required=false simply prevents the exception when no proper Person bean is found.)

EDIT: As Mr. Roddy, the Roddy of the Frozen Peas, pointed out, it would also be possible to add a different constructor for spring to create your bean, e.g. by annotating your repository with @NoArgsConstructor

sfiss
  • 2,119
  • 13
  • 19
  • 1
    In theory one could also add a no-args constructor for Spring to prefer: `@NoArgsConstructor` – Roddy of the Frozen Peas Jul 03 '19 at 19:13
  • Yes, I assume that he needs the quadrillion annotations just like he had on the repository :P But I think I'll mention it, good point, thanks – sfiss Jul 03 '19 at 19:14
  • @Autowired(required = false) does not work because it means inject the object, but if you don't find this object don't throow an exception. – xmen-5 Jul 03 '19 at 19:26
  • NoArgsConstructor works perfectly, in my opinion because there is no Autowired annotation on the list but on the no arg constructor. could someone confirm that. – xmen-5 Jul 03 '19 at 19:28
  • zak zak, the compiler (and neither does lombok with its default setup) does not magically add annotations. It's simply not injected because spring tries to inject all parameters of your constructor, and if you have none, nothing gets injected (provided field/setter injection is not used). – sfiss Jul 03 '19 at 19:31
  • I'd highly recommend not to combine several quite complex technologies unless it's really necessary. So better exclude Lombok for now and play with pure Java and Spring. After all, Lombok does not add any extra functionality, it's just a tool to save a few lines of code. And if you use modern IDE, you don't write this code anyway, as it's generated for you automatically. – stepio Jul 03 '19 at 19:42
  • 1
    @stepio, I agree that one should know about the technologies that are used and use them appropriately. However, Lombok is also about _reading_ less boilerplate (no source, but someone said you read code 10x as often as you write it). The OP should think whether all those lombok annotations are necessary (my opinion: they are really bad at that spot). – sfiss Jul 03 '19 at 19:44