Feature Request: MicroProfile-config integration: Allow injecting annotations with jakarta.inject.Qualifier (original) (raw)

I would like to integrate with MicroProfile Config. I got pretty far along, but… in order to allow Guice to allow @ConfigProperty, I had to do some very nasty reflection to muck with the innards of the strategyFor so that ensureIsBindingAnnotation(annotationType); would pass and allow me to Key.get(someType, someConfigPropertyAnnotation).

Ultimately, I would like to bind the @ConfigProperty and, of course, if this snippet can be made to work, any solution is awesome:

package org.example;

import com.google.common.reflect.ClassPath; import com.google.inject.AbstractModule; import com.google.inject.ConfigurationException; import com.google.inject.Key; import com.google.inject.Provider; import com.google.inject.name.Names; import com.google.inject.spi.Message; import io.smallrye.config.SmallRyeConfigBuilder; import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.slf4j.Logger; import org.slf4j.LoggerFactory;

import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.util.Collections; import java.util.HashSet; import java.util.Set;

public class MPConfigModule extends AbstractModule {

private static final Logger LOGGER = LoggerFactory.getLogger(MPConfigModule.class);

@Override
protected void configure() {

    SmallRyeConfigBuilder configBuilder = new SmallRyeConfigBuilder()
        .addDefaultSources()
        .addDefaultInterceptors()
        .addDiscoveredSources()
        .addDiscoveredConverters()
        .addDiscoveredInterceptors();

    Provider<Config> configProvider = getProvider(Config.class);

    try {
        for (ClassPath.ClassInfo clsInfo : ClassPath.from(ClassLoader.getSystemClassLoader()).getAllClasses()) {
            try {
                if (clsInfo.getSimpleName().equals("module-info")) {
                    continue;
                }
                Class<?> cls;
                cls = clsInfo.load();
                Set<Key<?>> seen = new HashSet<>();

                for (Constructor<?> constructor : cls.getDeclaredConstructors()) {
                    if (null != constructor.getDeclaredAnnotation(com.google.inject.Inject.class)
                        || null != constructor.getDeclaredAnnotation(javax.inject.Inject.class)) {
                        LOGGER.debug("constructor {}", constructor);
                    }
                    for (Parameter parameter : constructor.getParameters()) {
                        ConfigProperty configProperty = parameter.getDeclaredAnnotation(ConfigProperty.class);
                        if (null == configProperty) {
                            continue;
                        }
                        Class<?> tpe = parameter.getType();
                        LOGGER.debug("method {} {} ", tpe, configProperty);
                        Key<?> key = Key.get(tpe, configProperty);
                        if (seen.add(key)) {
                            String name = configProperty.name();
                            String defaultValue = configProperty.defaultValue();
                            if (defaultValue != null) {
                                configBuilder.withDefaultValue(name, defaultValue);
                            }
                            //noinspection unchecked
                            bind((Key<Object>) key).toProvider(() -> configProvider.get().getValue(name, tpe));
                        }
                    }
                }
                for (Field field : cls.getDeclaredFields()) {
                    ConfigProperty configProperty = field.getDeclaredAnnotation(ConfigProperty.class);
                    if (null == configProperty) {
                        continue;
                    }
                    if (null != field.getDeclaredAnnotation(com.google.inject.Inject.class)
                        || null != field.getDeclaredAnnotation(javax.inject.Inject.class)) {
                        Class<?> tpe = field.getType();
                        LOGGER.debug("field {} {} ", tpe, configProperty);
                        Key<?> key = Key.get(tpe, configProperty);
                        if (seen.add(key)) {
                            String name = configProperty.name();
                            String defaultValue = configProperty.defaultValue();
                            if (defaultValue != null) {
                                configBuilder.withDefaultValue(name, defaultValue);
                            }
                            //noinspection unchecked
                            bind((Key<Object>) key).toProvider(() -> configProvider.get().getValue(name, tpe));
                        }
                    }
                }
                for (Method method : cls.getDeclaredMethods()) {
                    if (null != method.getDeclaredAnnotation(com.google.inject.Inject.class)
                        || null != method.getDeclaredAnnotation(javax.inject.Inject.class)) {
                        for (Parameter parameter : method.getParameters()) {
                            ConfigProperty configProperty = parameter.getDeclaredAnnotation(ConfigProperty.class);
                            if (null == configProperty) {
                                continue;
                            }
                            Class<?> tpe = parameter.getType();
                            LOGGER.debug("method {} {} ", tpe, configProperty);
                            Key<?> key = Key.get(tpe, configProperty);
                            if (seen.add(key)) {
                                String name = configProperty.name();
                                String defaultValue = configProperty.defaultValue();
                                if (defaultValue != null) {
                                    configBuilder.withDefaultValue(name, defaultValue);
                                }
                                //noinspection unchecked
                                bind((Key<Object>) key).toProvider(() -> configProvider.get().getValue(name, tpe));
                            }
                        }
                    }
                }
            } catch (NoClassDefFoundError e) {
                LOGGER.debug("Error loading class {}", clsInfo, e);
            }
        }
        bind(Config.class).toInstance(configBuilder.build());
    } catch (IOException e) {
        throw new ConfigurationException(Collections.singleton(new Message(e.getLocalizedMessage())));
    }
}

}