/**
 * Copyright (C) 2012-2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package ninja;

import com.google.inject.Inject;
import com.google.inject.Injector;
import ninja.utils.NinjaTestServer;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;

/**
 * <p>
 * NinjaRunner makes it easy to test DAOs and service objects.
 * Service objects are generally the place where business logic executed.
 * Each service object may be injected a lot of DAOs.
 * </p>
 *
 * <p>
 * Suppose you have some service objects ,
 * without NinjaRunner , the only way to test service objects is to getInstance() of these DAOs
 * from Guice's injector and manually constructor-injecting to the service object
 * in NinjaTest's {@code @Before} method.
 * </p>
 *
 * <p>
 * With NinjaRunner , you just add {@code @RunWith(NinjaRunner.class)} to your test class ,
 * and declare {@code @Inject private ServiceObj serviceObj;} and you'll get an
 * injected serviceObj. No more {@code @Before} methods.
 * </p>
 *
 * <p>
 *     Code Example :
 * </p>
 *
 * <pre>
 * {@code &#064;RunWith(NinjaRunner.class)
 *   public class DataServiceTest  {
 *     &#064;Inject private ServiceObj serviceObj;
 *
 *     &#064;Test
 *     public void testDataService() {
 *       assert (serviceObj != null);
 *     }
 *   }
 * }
 * </pre>
 */
public class NinjaRunner extends BlockJUnit4ClassRunner {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private Injector injector = null;

    public NinjaRunner(Class<?> klass) throws InitializationError {
        super(klass);
        NinjaTestServer ninjaTestServer = new NinjaTestServer();
        injector = ninjaTestServer.getInjector();
    }

    @Override
    protected Object createTest() throws Exception {
        Object testObj = super.createTest();

        for (Field field : testObj.getClass().getDeclaredFields()) {
            if (field.isAnnotationPresent(Inject.class) || field.isAnnotationPresent(javax.inject.Inject.class)) {
                Object value = injector.getInstance(field.getType());
                logger.debug("try to inject {} to {}", value, testObj);
                try {
                    if (field.isAccessible()) {
                        field.set(testObj, value);
                    } else {
                        field.setAccessible(true);
                        field.set(testObj, value);
                        field.setAccessible(false);
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

        return testObj;
    }

}


@@ -639,41 +639,8 @@
 a;%0A%0A
-import com.google.inject.Inject;%0A
 impo
@@ -869,41 +869,8 @@
 y;%0A%0A
-import java.lang.reflect.Field;%0A%0A
 /**%0A
@@ -2407,25 +2407,24 @@
 Test();%0A
-%0A
         
 for (Fie
@@ -2419,788 +2419,40 @@
     
-for (Field field : testObj.getClass().getDeclaredFields()) %7B%0A            if (field.isAnnotationPresent(Inject.class) %7C%7C field.isAnnotationPresent(javax.inject.Inject.class)) %7B%0A                Object value = injector.getInstance(field.getType());%0A                logger.debug(%22try to inject %7B%7D to %7B%7D%22, value, testObj);%0A                try %7B%0A                    if (field.isAccessible()) %7B%0A                        field.set(testObj, value);%0A                    %7D else %7B%0A                        field.setAccessible(true);%0A                        field.set(testObj, value);%0A                        field.setAccessible(false);%0A                    %7D%0A                %7D catch (IllegalAccessException e) %7B%0A                    e.printStackTrace();%0A                %7D%0A            %7D%0A        %7D%0A
+injector.injectMembers(testObj);
 %0A   
@@ -2478,12 +2478,11 @@
 ;%0A    %7D%0A
-%0A
 %7D%0A%0A

Modify NinjaRunner to make use of injector's built-in injectMembers(obj)