Sandheep
Sandheep

Reputation: 517

How to give property placeholder support for java custom annotation

I have created a custom Java annotation and has certain attributes. How can I support the property placeholder for string attributes ?

Eg:

Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PublishEvent {

    public EventStore eventStore();
    public boolean isPersistent() default false;
    public String channelName();


}

I want to use as :

@PublishEvent(channelName="${rabbit.event.default}")
public void someMethod(){}

where rabbit.event.default is a key for a property defined in application.properties file. I want to have the property key replaced with value as in the case of @Value annotations of spring.

I am using Spring AOP to intercept the annotation and do processing.

Upvotes: 2

Views: 3322

Answers (2)

RJ.Hwang
RJ.Hwang

Reputation: 1913

I Use org.springframework.util.StringValueResolver#resolveStringValue method to resolve the placeholer value. May be the bellow sample code can help you:

@Configuration
public class PublishEventConfiguration implements ApplicationContextAware, EmbeddedValueResolverAware {
  private ApplicationContext context;
  private StringValueResolver resolver;

  @Override
  public void setApplicationContext(ApplicationContext context) throws BeansException {
    this.context = context;
  }

   @Override
  public void setEmbeddedValueResolver(StringValueResolver resolver) {
    this.resolver = resolver;
  }


  @PostConstruct
  public void init() throws Exception {
    Collection<Object> publishEvents = context.getBeansWithAnnotation(PublishEvent.class).values();
    for (Object v : publishEvents) {
      PublishEvent cfg = v.getClass().getAnnotation(PublishEvent.class);
      String channelName = resolver.resolveStringValue(cfg.channelName());
    }
  }
}

Upvotes: 2

Sandheep
Sandheep

Reputation: 517

As I was not able to find a built-in method for enriching the annotation attributes with property value, I ended up creating a utility class that does the same.

@Component
public class IntegrationUtils {

    @Autowired
    private Environment environment;

    @Resource
    private HashMap<String,String> propertyMapping;


    /**
     * Method to check if the text passed is a property and get the value
     * from the environment.
     *
     * @param text  : The text to be matched for the property
     * @return      : The property value if its starting with $ and has a matching value in
     *                environment
     *                Return the text itself is nothing matching
     */
    public String getEnvironmentProperty(String text) {

        // Check if the text is already been parsed
        if ( propertyMapping.containsKey(text)) {

            return propertyMapping.get(text);

        }


        // If the text does not start with $, then no need to do pattern
        if ( !text.startsWith("$") ) {

            // Add to the mapping with key and value as text
            propertyMapping.put(text,text);

            // If no match, then return the text as it is
            return text;

        }

        // Create the pattern
        Pattern pattern = Pattern.compile("\\Q${\\E(.+?)\\Q}\\E");

        // Create the matcher
        Matcher matcher = pattern.matcher(text);

        // If the matching is there, then add it to the map and return the value
        if( matcher.find() ) {

            // Store the value
            String key = matcher.group(1);

            // Get the value
            String value = environment.getProperty(key);

            // Store the value in the setting
            if ( value != null ) {

                // Store in the map
                propertyMapping.put(text,value);

                // return the value
                return value;

            }

        }

        // Add to the mapping with key and value as text
        propertyMapping.put(text,text);

        // If no match, then return the text as it is
        return text;

    }

}

Upvotes: 0

Related Questions