// Path: src/main/java/com/github/vbauer/herald/injector/LoggerInjector.java
// public final class LoggerInjector {
// 
//     private static final Collection<LogFactory> LOG_FACTORIES = loadLogFactories();
// 
// 
//     private LoggerInjector() {
//         throw new UnsupportedOperationException();
//     }
// 
// 
//     public static void inject(final Object... beans) {
//         if (beans != null) {
//             for (final Object bean : beans) {
//                 inject(bean);
//             }
//         }
//     }
// 
//     public static <T> T inject(final T bean) {
//         if (bean != null) {
//             final Class<?> beanClass = bean.getClass();
//             final Field[] declaredFields = beanClass.getDeclaredFields();
// 
//             for (final Field field : declaredFields) {
//                 if (needToInjectLogger(beanClass, field)) {
//                     injectLogger(bean, field);
//                 }
//             }
//         }
//         return bean;
//     }
// 
// 
//     /*
//      * Internal API.
//      */
// 
//     private static boolean needToInjectLogger(final Class<?> beanClass, final Field field) {
//         final boolean hasAnnotation = beanClass.getAnnotation(Log.class) != null;
//         if (hasAnnotation) {
//             final Class<?> fieldType = field.getType();
//             return LogFactoryDetector.hasCompatible(LOG_FACTORIES, fieldType);
//         }
//         return field.getAnnotation(Log.class) != null;
//     }
// 
//     private static void injectLogger(final Object bean, final Field field) {
//         final boolean isAccessible = field.isAccessible();
//         ReflectionUtils.setAccessible(field, true);
// 
//         // Read context parameters.
//         final Class<?> beanClass = bean.getClass();
//         final Class<?> loggerClass = field.getType();
//         final Log annotation = ReflectionUtils.findAnnotation(Log.class, beanClass, field);
// 
//         final boolean required = annotation.required();
//         final String loggerName = annotation.value();
// 
//         try {
//             final Object logger = createLogger(beanClass, loggerClass, loggerName);
//             field.set(bean, logger);
//         } catch (final Throwable ex) {
//             if (required) {
//                 ReflectionUtils.handleReflectionException(ex);
//             }
//         } finally {
//             ReflectionUtils.setAccessible(field, isAccessible);
//         }
//     }
// 
//     private static Object createLogger(
//         final Class<?> beanClass, final Class<?> loggerClass, final String loggerName
//     ) {
//         // Find corresponding logger factory.
//         final LogFactory logFactory =
//             LogFactoryDetector.findCompatible(LOG_FACTORIES, loggerClass);
// 
//         if (logFactory == null) {
//             throw new MissedLogFactoryException(loggerClass);
//         }
// 
//         // Create logger.
//         final Object logger = !loggerName.isEmpty()
//             ? logFactory.createLogger(loggerName) : logFactory.createLogger(beanClass);
// 
//         if (logger == null) {
//             throw new LoggerInstantiationException(logFactory);
//         }
//         return logger;
//     }
// 
//     private static Collection<LogFactory> loadLogFactories() {
//         return ServiceLoaderUtils.load(LogFactory.class);
//     }
// 
// }


import com.github.vbauer.herald.injector.LoggerInjector;
import com.google.inject.AbstractModule;
import com.google.inject.TypeLiteral;
import com.google.inject.matcher.Matcher;
import com.google.inject.matcher.Matchers;
import com.google.inject.spi.InjectionListener;
import com.google.inject.spi.TypeEncounter;
import com.google.inject.spi.TypeListener;
package com.github.vbauer.herald.ext.guice;


/**
 * Guice {@link AbstractModule} which injects initialized loggers in beans.
 *
 * @author Vladislav Bauer
 */

public class LogModule extends AbstractModule {

    private final Matcher<Object> typeMatcher;


    public LogModule() {
        this(Matchers.any());
    }

    public LogModule(final Matcher<Object> typeMatcher) {
        this.typeMatcher = typeMatcher;
    }


    /**
     * {@inheritDoc}
     */
    @Override
    protected void configure() {
        bindListener(typeMatcher, createTypeListener());
    }


    private TypeListener createTypeListener() {
        return new TypeListener() {
            @Override
            public <I> void hear(final TypeLiteral<I> typeLiteral, final TypeEncounter<I> typeEncounter) {
// Path: src/main/java/com/github/vbauer/herald/injector/LoggerInjector.java
// public final class LoggerInjector {
// 
//     private static final Collection<LogFactory> LOG_FACTORIES = loadLogFactories();
// 
// 
//     private LoggerInjector() {
//         throw new UnsupportedOperationException();
//     }
// 
// 
//     public static void inject(final Object... beans) {
//         if (beans != null) {
//             for (final Object bean : beans) {
//                 inject(bean);
//             }
//         }
//     }
// 
//     public static <T> T inject(final T bean) {
//         if (bean != null) {
//             final Class<?> beanClass = bean.getClass();
//             final Field[] declaredFields = beanClass.getDeclaredFields();
// 
//             for (final Field field : declaredFields) {
//                 if (needToInjectLogger(beanClass, field)) {
//                     injectLogger(bean, field);
//                 }
//             }
//         }
//         return bean;
//     }
// 
// 
//     /*
//      * Internal API.
//      */
// 
//     private static boolean needToInjectLogger(final Class<?> beanClass, final Field field) {
//         final boolean hasAnnotation = beanClass.getAnnotation(Log.class) != null;
//         if (hasAnnotation) {
//             final Class<?> fieldType = field.getType();
//             return LogFactoryDetector.hasCompatible(LOG_FACTORIES, fieldType);
//         }
//         return field.getAnnotation(Log.class) != null;
//     }
// 
//     private static void injectLogger(final Object bean, final Field field) {
//         final boolean isAccessible = field.isAccessible();
//         ReflectionUtils.setAccessible(field, true);
// 
//         // Read context parameters.
//         final Class<?> beanClass = bean.getClass();
//         final Class<?> loggerClass = field.getType();
//         final Log annotation = ReflectionUtils.findAnnotation(Log.class, beanClass, field);
// 
//         final boolean required = annotation.required();
//         final String loggerName = annotation.value();
// 
//         try {
//             final Object logger = createLogger(beanClass, loggerClass, loggerName);
//             field.set(bean, logger);
//         } catch (final Throwable ex) {
//             if (required) {
//                 ReflectionUtils.handleReflectionException(ex);
//             }
//         } finally {
//             ReflectionUtils.setAccessible(field, isAccessible);
//         }
//     }
// 
//     private static Object createLogger(
//         final Class<?> beanClass, final Class<?> loggerClass, final String loggerName
//     ) {
//         // Find corresponding logger factory.
//         final LogFactory logFactory =
//             LogFactoryDetector.findCompatible(LOG_FACTORIES, loggerClass);
// 
//         if (logFactory == null) {
//             throw new MissedLogFactoryException(loggerClass);
//         }
// 
//         // Create logger.
//         final Object logger = !loggerName.isEmpty()
//             ? logFactory.createLogger(loggerName) : logFactory.createLogger(beanClass);
// 
//         if (logger == null) {
//             throw new LoggerInstantiationException(logFactory);
//         }
//         return logger;
//     }
// 
//     private static Collection<LogFactory> loadLogFactories() {
//         return ServiceLoaderUtils.load(LogFactory.class);
//     }
// 
// }


// Path: src/main/java/com/github/vbauer/herald/ext/guice/LogModule.java
import com.github.vbauer.herald.injector.LoggerInjector;
import com.google.inject.AbstractModule;
import com.google.inject.TypeLiteral;
import com.google.inject.matcher.Matcher;
import com.google.inject.matcher.Matchers;
import com.google.inject.spi.InjectionListener;
import com.google.inject.spi.TypeEncounter;
import com.google.inject.spi.TypeListener;

package com.github.vbauer.herald.ext.guice;


/**
 * Guice {@link AbstractModule} which injects initialized loggers in beans.
 *
 * @author Vladislav Bauer
 */

public class LogModule extends AbstractModule {

    private final Matcher<Object> typeMatcher;


    public LogModule() {
        this(Matchers.any());
    }

    public LogModule(final Matcher<Object> typeMatcher) {
        this.typeMatcher = typeMatcher;
    }


    /**
     * {@inheritDoc}
     */
    @Override
    protected void configure() {
        bindListener(typeMatcher, createTypeListener());
    }


    private TypeListener createTypeListener() {
        return new TypeListener() {
            @Override
            public <I> void hear(final TypeLiteral<I> typeLiteral, final TypeEncounter<I> typeEncounter) {
                typeEncounter.register((InjectionListener<I>) LoggerInjector::inject);