Results 1 to 6 of 6

Thread: Using internal classes with Spring

  1. #1
    Join Date
    Apr 2005
    Posts
    3

    Default Using internal classes with Spring

    We are using Spring.Net for dependency injection at my company, DigitalFocus. It has worked out very well for us and aided us greatly in unit testing. There has only been one major snag, and it involves trying to use Spring.Net to inject internal classes. Internal classes are a good place to put plumbing that needs to be used inside an assembly that shouldn't be accessed directly from outside the assembly (such as low level database access code).

    In order to inject an internal class into a public class, the property used for injection must also be internal (or else the compiler complains - inconsistent accessibility). This also is true for constructor or factory method injection. The problem is that Spring.Net does not use the NonPublic binding flag when looking for the property, constructor, or factory method to use for injection. I have been able to modify the Spring.Net code to make this work, but would like to know the intent in not allowing non-public members to participate in injection.

    For reference, here are the 3 changes I made:

    Spring.Objects.ObjectWrapper, changed a constant on line 110 (added BindingFlags.NonPublic):

    private const BindingFlags PropertyResolutionFlags =
    BindingFlags.Public
    | BindingFlags.NonPublic
    | BindingFlags.SetProperty
    | BindingFlags.Static
    | BindingFlags.Instance
    | BindingFlags.IgnoreCase;

    Spring.Objects.Factory.Support.AbstractAutowireCap ableObjectFactory, changed line 971 in method: protected IObjectWrapper AutowireConstructor (string objectName, RootObjectDefinition definition)

    ConstructorInfo[] constructors = definition.ObjectClass.GetConstructors(BindingFlag s.Public | BindingFlags.NonPublic | BindingFlags.Instance);

    Spring.Objects.Factory.Support.AbstractAutowireCap ableObjectFactory, changed line 781 in method: protected virtual IObjectWrapper InstantiateUsingFactoryMethod (string objectName, RootObjectDefinition definition, object [] arguments)

    BindingFlags methodFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase;

  2. #2
    Join Date
    Apr 2005
    Posts
    3

    Default

    The version of Spring that I changed was actually release candidate 1. For anyone interested, only 2 changes had to be made for release candidate 3 (the most recent as of this writing):

    Spring.Objects.ObjectWrapper, line 114 changed constant:

    private const BindingFlags PropertyResolutionFlags =
    BindingFlags.Public
    | BindingFlags.NonPublic
    | BindingFlags.SetProperty
    | BindingFlags.Static
    | BindingFlags.Instance
    | BindingFlags.IgnoreCase;

    Spring.Objects.Factory.Support.AbstractAutowireCap ableObjectFactory, line 809 of method: protected virtual IObjectWrapper InstantiateUsingFactoryMethod(string name, RootObjectDefinition definition, object[] arguments):

    BindingFlags methodFlags = BindingFlags.Public | BindingFlags.NonPublic| BindingFlags.IgnoreCase;

  3. #3
    Mark Pollack is offline Spring.NET Co-Lead Spring TeamSpring User
    Join Date
    Sep 2004
    Location
    New York, NY
    Posts
    1,683

    Default

    Hi Maggy,

    I'd be inclined to add this - though DI is normally about injection of public properties there are valid reasons for performing DI on non public properties in certain cases. It might be a good idea to disable this behavior by adding a top level property to the context - much like auto-wire so that public property DI purists can have a measure of control over this behavior. I'll run it by the other developers and also the Spring.Java guys. Thanks for such a detailed posting!

    Cheers,
    Mark

  4. #4
    Join Date
    Sep 2004
    Location
    Belgrade, Serbia
    Posts
    613

    Default

    I'm inclined to allow this as well. In some cases I'd like to be able to make injected properties private, so they are not (as easily) accessible from the client code.

    I don't fully understand the reason for making them internal, though. If the only classes you can assign to them are internal to the assembly, why use DI at all -- you could simply hardcode which class to use. Unless you are packaging both production classes and their corresponding test stubs into the same assembly, of course.

    In that case, you could also make the property public, use the appropriate public interface as its type, and make internal class implement that same public interface. That way you get the ability to inject an instance of the internal class while being able to replace it with other, external implementation during testing.

    I guess it boils down to how you want to ship your test stubs. My personal preference is to have them in a separate assembly, but I can see the value of keeping them in the same assembly with the classes they replace -- for one, it makes them much easier to find when you need them :wink:

    - Aleks

  5. #5
    Join Date
    Apr 2005
    Posts
    3

    Default thanks for the response

    Thanks for your quick replies. Here's some more in depth info on our situation:

    We don't want to hardcode the references to our internal classes for testing reasons - using DI makes testing each layer separately a breeze. Our specific case for wanting internal classes is that we have public Manager classes that are responsible for security, business logic, etc. We also have Dao classes that simply interface with the DB. The Daos should not be accessed directly outside the assembly, but we do want to use DI to inject them into the managers to make testing cleaner (we frequently use NMock to mock out injected classes).

    Using a public interface with an internal class does work, but we have no need to make the interface to the dao public (and would prefer not to simply to accommodate our chosen frameworks). All our tests are contained inside the assemblies they test, with different build scripts including or excluding them as appropriate for each environment.

    I noticed that with Spring.Net release candidate 3 non-public constructor injection is supported already. It would be great if property and factory method injection could also support non-public injection. If it were configurable all the better.

    Thanks very much!

  6. #6
    Join Date
    Sep 2004
    Location
    Belgrade, Serbia
    Posts
    613

    Default

    Yeah, exactly the scenario I had in mind...

    I'd say we should support non-public injection. It allows people to choose property and class visibility based on their needs instead of framework requirements. I really don't see the need to impose artifical requirements such as this one on the users.

    The only issue I see with it is that it makes application somewhat tied to Spring because it's not possible to inject collaborators directly by simply setting a property -- you'd have to use reflection. But then again, tying or not tying application to Spring is a decision users should be allowed to make.

    - Aleks

Similar Threads

  1. Spring + remoting + IIS
    By legabertrand in forum Remoting and Web Services
    Replies: 14
    Last Post: 09-11-2007, 04:17 PM
  2. Spring and concurrent components
    By Tesuji in forum Architecture, Design and Best Practices
    Replies: 1
    Last Post: 08-29-2005, 03:42 PM
  3. How to express a common factory idiom using Spring
    By rmoskal in forum Core Container
    Replies: 3
    Last Post: 06-12-2005, 08:31 PM
  4. what are you injecting with Spring.Net?
    By SecretSquirrel123 in forum Core Container
    Replies: 7
    Last Post: 04-27-2005, 08:11 AM
  5. spring components as web services
    By robbo_b in forum Remoting and Web Services
    Replies: 4
    Last Post: 04-06-2005, 12:29 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •