Search code examples
javaspringintellij-idea

Making IntelliJ aware of my custom field injection mechanism


I wrote a simple BeanPostProcessor to get more familiar with how Spring works

package org.example.demos.beanPostProcessor;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App {
    public static void main(String[] args) {
        var context = new AnnotationConfigApplicationContext(Config.class);
        Sage sage = context.getBean("sage", Sage.class);
        sage.sayWisdom();
    }
}
package org.example.demos.beanPostProcessor;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class Config {
}
package org.example.demos.beanPostProcessor;

import org.springframework.stereotype.Component;

@Component
public class Sage {
    @Wisdom
    private String wisdom; // "never assigned"

    public void sayWisdom() {
        String processedWisdom = process(wisdom);
        System.out.println(processedWisdom);
    }

    private String process(String wisdom) {
        String intro = getIntro();
        String wiserWisdom = makeItSoundWiser(wisdom);
        return intro + " " + wiserWisdom;
    }

    private String getIntro() {
        return "Sage says:";
    }

    private String makeItSoundWiser(String wisdom) {
        return wisdom.replaceAll("\\.(?=\\s|$)|(?<!\\.)(?=$)", "...");
    }
}
package org.example.demos.beanPostProcessor;

import org.springframework.stereotype.Component;

@Component
public class SimpleWisdomProvider implements WisdomProvider {
    private final String[] wisdoms = {
            "Tomorrow is often the busiest day of the week.",
            "I have always wanted to be somebody, but I see now I should have been more specific.",
            "Knowledge is like underwear. It is useful to have it, but not necessary to show it off.",
            "Go to Heaven for the climate, Hell for the company.",
            "Going to church doesn’t make you a Christian any more than going to a garage makes you an automobile."
    };

    @Override
    public String getWisdom() {
        int randomIndex = ThreadLocalRandom.current().nextInt(wisdoms.length);
        return wisdoms[randomIndex];
    }
}
package org.example.demos.beanPostProcessor;

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Wisdom {
}
package org.example.demos.beanPostProcessor;

import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.Objects;

@Component
@RequiredArgsConstructor
public class WisdomBeanPostProcessor implements BeanPostProcessor {
    private final WisdomProvider wisdomProvider;
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Field[] fields = bean.getClass().getDeclaredFields();
        for (Field field : fields) {
            Wisdom wisdom = field.getAnnotation(Wisdom.class);
            if (Objects.nonNull(wisdom)) {
                field.setAccessible(true);
                ReflectionUtils.setField(field, bean, wisdomProvider.getWisdom());
                break;
            }
        }
        return bean;
    }
}
package org.example.demos.beanPostProcessor;

public interface WisdomProvider {
    String getWisdom();
}

It works, but I wonder whether I can make IntelliJ aware of my initialization mechanism so that I don't get a warning

Private field 'wisdom' is never assigned

Slapping @SuppressWarnings onto my wisdom field is ugly. I tried hiding it within the @Wisdom annotation, but it's apparently not really transitive so the warning is still present. Of course, I don't want to disable the warning altogether

What are my options?


Solution

  • Type Alt+Enter on the warning and select Assume field annotated by @Wisdom as implicitly written in the intention list that appears. Now any field annotated by @Wisdom will no longer be reported as not assigned.

    This will add the annotation to the "Unused declaration" inspection's settings. You can remove it again, by going the settings of this inspection, selecting the Entry Points tab, and clicking the Annotations button. The annotation name will be in the bottom list of the dialog that appears.

    inspection settings visual guide