Robert R Evans
Robert R Evans

Reputation: 177

in order to inject a class with Guice, the substituted class must be passed as an object argument to the constructor?

Is it true that in order to inject a class with Guice, the substituted class must be passed as an object argument to the constructor? I think this is "of course", but I thought I'd ask.

I wrote a class-under-test (CUT) with two constructors. One constructor takes one argument, an object of type depended-on-component (DOC). The other constructor calls the first, passing a new DOC(). The unit test uses an injector to direct the CUT to use MockDOC instead of DOC. When I remove the default CUT(), the unit test gets a run time error: com.google.inject.internal.ComputationException: java.lang.NoClassDefFoundError: org/objectweb/asm/ClassVisitor

The code:

//The class under test:
public class CUT {
    DOC m_DOC;

    @Inject
    public CUT(DOC doc)
    {
        m_DOC = doc;
    }

    // When this ctor is added, there is a run time error:
    // com.google.inject.internal.ComputationException: java.lang.NoClassDefFoundError: org/objectweb/asm/ClassVisitor
//    @Inject
//    public CUT()
//    {
//       this(new DOC());
//    }

    public boolean getVal()
    {
        return m_DOC.getVal();
    }
}

    // The depended-on-component:
public class DOC {
    @Inject
    public DOC()
    {

    }

    // The REAL DOC returns 'true' MockDOC will return false
    public Boolean getVal()
    {
        return true;
    }
}

The mock DOC:

     // This is the class we want CUT to call during unit test
class MockDOC extends DOC
{
    @Override
    public Boolean getVal()
    {
        // Real DOC returns 'true'. We return false so unit tester knows we got injected
        return false;
    }
}

The unit test that uses MockDOC to test CUT:

    // Test the CUT class by substituting a mock for CUT's DOC
public class CUTTest {

    @Test
    public void testGetVal() throws Exception {
        // Direct Guice to inject our MockDOC for CUT's use of DOC
        Injector m_injector = Guice.createInjector(new CUTTestModule());

        // Ask Guice to create a CUT object
        CUT cut = m_injector.getInstance(CUT.class);

        // The DOC returns 'true', while the mock DOC returns 'false. So we'll get 'false' if the injection
        // succeeded
        assertEquals(cut.getVal(), false);
    }

    // The class that we will pass to Guice to direct its injection
    class CUTTestModule implements Module {
        public CUTTestModule()
        {
            super();
        }

        @Override
        public void configure(Binder binder) {
            binder.bind(DOC.class).to(MockDOC.class);
        }
    }
}

Upvotes: 0

Views: 144

Answers (1)

robert
robert

Reputation: 978

First, you can use Guice injection also on fields.

But regarding your main problem... why do add the @Inject annotation to the default constructor (the one without parameters)? There is no parameter to inject.

// When this ctor is added, there is a run time error:
    // com.google.inject.internal.ComputationException: java.lang.NoClassDefFoundError: org/objectweb/asm/ClassVisitor
//    @Inject
//    public CUT()
//    {
//       this(new DOC());
//    }

I would remove the @Inject

Upvotes: 1

Related Questions