简体   繁体   中英

List with Bean in spring

I having an user details class inside that i placed address class to store the multiple addressess for each user details class. I am using Spring 4.0 for that. Below given the code:

UserDetails class:

@Component("userDetails")

public class UserDetails {

    @Resource(name="address")
    @Autowired
    private List<Address> address;
    public List<Address> getAddress() {
        return address;
    }
    @Autowired
    public void setAddress(List<Address> address) {
        this.address = address;
    }
}

Address Class:

@Component("address")

public class Address {

    private String area;

    public String getArea() {
        return area;
    }
    public void setArea(String area) {
        this.area = area;
    }
}

In this example, Address.area value need to pass in the run time and then i need to create an object for Address class. Then it need to add in the List address variable present inside UserDetails class. Likewise i need to add n number object in the arrayList then i need to create an object for UserDetails class.

I tried the below code:

public class AppMain {

    public static void main(String args[]){
        AbstractApplicationContext  context = new AnnotationConfigApplicationContext(AppConfig.class);

        Address address = (Address)context.getBean("address");
        //setting first value:
        address.setArea("XXX");

        Address address1 = (Address)context.getBean("address");
        //setting second value
        address1.setArea("YYY");

        UserDetails userDetails = (UserDetails)context.getBean("userDetails");
        System.out.println("User Size: "+application.getAddress().size());
        System.out.println("User Details : "+application.getAddress().get(0).getArea());
        System.out.println("User Details : "+application.getAddress().get(1).getArea()); // getting ArrayIndexOutOfBoundException in this line
    }
}

partial Output: User Size: 1 User Details : YYY

Expected Output: User Size: 2 User Details : XXX User Details : YYY

Could you please help with this.

It's not entirely clear to me why you would want to create what appear to be domain objects using Spring but it looks like that's what you're doing from your code.

Spring has the concept of Scope that controls what happens when you retrieve a bean from an ApplicationContext . The default Scope is singleton which means you only get a one instance of the bean within the ApplicationContext . This means that your calls context.getBean("address") always return the same object.

As for the wiring that you've performed using the @Component annotation; this occurs when the classpath is scanned (normally when the application starts). At this time Spring instantiates a single instance of each class marked with @Component , that's one Address and one UserDetails . Spring is smart enough to add the single Address to a List before setting the address field but that's all it does.

Your code then retrieves this objects from the ApplicationContext setting the area on the same object twice, hence why the debug statements print as they do.

This explains what's going on with your code, but leaves the question of how to fix it unanswered.

As I said, I can't understand why you would used Spring to build what appears to be a domain model. Domain models, in terms of the instances of each class, are not typically known ahead of time and therefore Spring is not the appropriate tool to use to create such a model (Spring is typically used to wire together the application itself).

You should modify the domain classes' constructors like this:

public Address
{
  private String area;

  public Address(String area)
  {
    this.area = area;
  }

  ...
}

public UserDetails
{
  private List<Address> addresses;

  public UserDetails(Address... addresses)
  {
    this.addresses = Arrays.asList(addresses);
  }

  ...
}

And then the main method can be re-written:

public static void main(String[] args)
{
   UserDetails userDetails = new UserDetails(
     new Address("XXX"),         
     new Address("YYY"),        
   ); 

   System.out.println("User Size: " + application.getAddress().size());
   System.out.println("User Details: " + application.getAddress().get(0).getArea());
   System.out.println("User Details: " + application.getAddress().get(1).getArea());
}

Notice that you are getting the same bean twice, so it's impossible that you get two injections in the UserDetails List:

Address address = (Address)context.getBean("address");
...
Address address1 = (Address)context.getBean("address");

Something like this should work:

@Configuration
public class AppConfig{

    @Bean
    public UserDetails userDetails(){
        return new UserDetails();
    }

    @Bean
    public Address addressXXX(){
        return new Address();
    }

    @Bean
    public Address addressYYY(){
        return new Address();
    }

}

Then your code:

Address address = (Address)context.getBean("addressXXX");
//setting first value:
address.setArea("XXX");

Address address1 = (Address)context.getBean("addressYYY");
//setting second value
address1.setArea("YYY");

UserDetails userDetails = (UserDetails)context.getBean("userDetails");
System.out.println("User Size: "+application.getAddress().size());
System.out.println("User Details : "+application.getAddress().get(0).getArea()); //--->XXX
System.out.println("User Details : "+application.getAddress().get(1).getArea()); //--->YYY

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM