views:

308

answers:

3

Hi

I have the following class structure

public class Outer{
    private Mapper a;
    ....

    private class MapperA implements Mapper {

    }

    private class MapperB implements Mapper {

    }
}

In my Spring config file I would like to create a an Outer bean, and assign one of MapperA or MapperB as a property. Is this possible?

<bean id="outer" class="mypackage.Outer">
    <property name="a" ?????='????' />
</bean>

Edit: Some more info, based on the feedback from answers:

  1. I got lazy with my above example. I do have a public setter/getter for the Mapper instance variable.

  2. The reason all of the Mapper classes are inner classes is because there could potentially be many of them, and they will only ever be used in this class. I just don't want a ton of cruft classes in my project. Maybe a factory method is a better idea.

+1  A: 

Normally you'd need a setter for the Mapper within Outer, and an instance of the required Mapper. But as these are:

  1. private
  2. inner

classes, that becomes a bit tricky (as you've identified). If you make them public, I'm sure you could creae an instance using Outer$MapperA etc. But that seems a little nasty. So:

  1. do they need to be inner and private ?
  2. perhaps Outer can take a String, and determine from that whether to instantiate MapperA or MapperB. i.e. there's some factory capability here.

The simplest thing to do is to really determine if they need to be inner/private. If so, then they really shouldn't be referenced within the config, which should be talking about publicly accessible classes.

Brian Agnew
Thanks, I decided to use a factory class for my Mappers.
darren
+1  A: 

As far as I know, it's impossible until you make MapperA and MapperB usual public classes.

But if you do want to keep them as inner private classes then you can "inject" them manually.

You'll need to create method with @PostInit annotation and initialize your a field there (a = new MapperA () for example, or something more complex). With this approach you should also check that initialization callbacks are switched-on in your spring configuration.

Roman
thanks for the suggestion. I always forget about the @PostInit annotations.
darren
+2  A: 

Spring can instantiate private inner classes. The actual problem with your config is that they are also non-static, so you need a <constructor-arg .../>:

<bean id="outer" class="mypackage.Outer"> 
    <property name = "a">
        <bean class = "mypackage.Outer.MapperA"> 
            <constructor-arg ref = "outer" />
        </bean>
    </property>
</bean> 
axtavt
Neat. I decided to go with a separate factory class, but this is good information. Thanks.
darren
I doubt this works. How can Spring actually create an instance of an inner class without an enclosing instance of Outer?
Willi
@Willi: Notice the `<constructor-arg .../>`. Non-static inner classes have an implicit constructor argument, pointing at the instance of enclosing class. To create non-static inner class using reflection, you should pass that argument explicitly.
axtavt
Mmh. Ok, i didn't now that. Quite interesting though.
Willi