Expand my Community achievements bar.

Guidelines for the Responsible Use of Generative AI in the Experience Cloud Community.

Java Custom Annotation

Avatar

Community Advisor

Hi members,

I am trying to create a custom annotation. The idea was very simple, it would set the data in a string field.

Here is the code I have done till now,

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface RunMode {

}
@component(service = Injector.class, immediate = true)
public class RunModeInjector implements Injector {
    @reference
    private AppSettingService appSettingService;

    @Override
    public String getName() {
        return "runmode";
    }

    @Override
    public @nullable Object getValue(@NotNull Object adaptable, String name, @notnull Type type,
                           @notnull AnnotatedElement annotatedElement,
                           @notnull DisposalCallbackRegistry disposalCallbackRegistry) {

        if (annotatedElement.isAnnotationPresent(RunMode.class)) {
            return appSettingService.getRunMode();
        }
        return null;
    }
}

Usages,

// Sling Model
// value is assigned
// But I was supposed to it will work without the extra @inject annotation.
@Inject @RunMode
private String runMode;


// OSGI Service/servlet
// value is null, 
// The annotatedElement.isAnnotationPresent(RunMode.class) condition is not satisfied from injector class.
@RunMode
private String runMode;

What I missed, or how to make it work? 

Thanks in advance.
 

3 Replies

Avatar

Community Advisor

Thanks for the related blogs. But those all are related to only sling model. Those are not working for service/servlet level.
However, I got an alternative solution, which is for service/servlet.

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;

@Component(immediate = true, service = OSGiFieldInjector.class)
public class OSGiFieldInjector {

    private static final Logger log = LoggerFactory.getLogger(OSGiFieldInjector.class);

    @reference
    private AppSettingService appSettingService;

    @activate
    protected void activate(ComponentContext context) {
        BundleContext bundleContext = context.getBundleContext();

        bundleContext.addServiceListener(event -> {
            ServiceReference<?> serviceReference = event.getServiceReference();
            Object serviceInstance = bundleContext.getService(serviceReference);
            injectRunModeFields(serviceInstance);
        });
    }

    private void injectRunModeFields(Object serviceInstance) {
        Field[] fields = serviceInstance.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(RunMode.class)) {
                try {
                    field.setAccessible(true);
                    String runModeValue = appSettingService.getRunMode();
                    field.set(serviceInstance, runModeValue);
                } catch (IllegalAccessException e) {
                    log.error("Failed to inject run mode into field", e);
                }
            }
        }
    }
}

But I don't like this solution, since it's behind-work complexity is too high.

Avatar

Administrator

@Sady_Rifat Did you find the suggestion helpful? Please let us know if you require more information. Otherwise, please mark the answer as correct for posterity. If you've discovered a solution yourself, we would appreciate it if you could share it with the community. Thank you!



Kautuk Sahni