0

Here is my class:

 public class DeduplicationErrorMetric extends AbstractErrorMetric {
    
        public static final String DEDUPLICATIONS_METRIC = "deduplications";
        public static final String KAFKA_MESSAGES_METRIC = "kafka.messages";
    
        private static String DEDUPLICATION_TOPIC_NAME;
    
        private static final List<Tag> DEDUPLICATION_ERROR_TAGS = List.of(Tag.of("type", "failed"));
        private static final List<Tag> KAFKA_ERROR_TAGS = List.of(Tag.of("topic", DEDUPLICATION_TOPIC_NAME),
                Tag.of("action", "send"), Tag.of("result", "failure"));
    
        public DeduplicationErrorMetric() {
            super(Map.of(
                    DEDUPLICATIONS_METRIC, DEDUPLICATION_ERROR_TAGS,
                    KAFKA_MESSAGES_METRIC, KAFKA_ERROR_TAGS
            ));
        }
    
        @Override
        public void incrementMetric(String key) {
            errorCounters.get(key).increment();
        }
    }

I have @Value("${kafka.topic.deduplication}") in my application.yml, and I need to insert the value into DEDUPLICATION_TOPIC_NAME before the bean will be created. How can I do it?

Maksym Rybalkin
  • 453
  • 1
  • 8
  • 22

3 Answers3

1

You can use the setter to do this but I'd advocate against this practice !

  1. This means your field will be null before a first instance comes and invokes this injection point
  2. Your static field is not final so can lead to modification, thus lead to hard to debug bugs
  3. It will not solve your current problem as the null value will be used in this case for KAFKA_ERROR_TAGS
@Value("${kafka.topic.deduplication}")
private void setDeduplicationTopicName(String deduplicationTopicName) {
    this.DEDUPLICATION_TOPIC_NAME = deducplicationTopicName;
}

Instead, maybe try to create a @Singleton bean and use @Value on its fields, then you're sure you have only one instance.

For your list, you can then use @PostConstruct to make sure it's instantiated once

Yassin Hajaj
  • 21,337
  • 9
  • 51
  • 89
1

What you could do here is to directly use injection from a properties file.

If it is a SpringBoot app, in you application properties set your kafka.topic.deduplication property (you can have different values for different environments).

This way, Spring will get the value while constructing the bean.

Your code could look something like this:

public class DeduplicationErrorMetric extends AbstractErrorMetric {

    public static final String DEDUPLICATIONS_METRIC = "deduplications";
    public static final String KAFKA_MESSAGES_METRIC = "kafka.messages";

    private static final List<Tag> DEDUPLICATION_ERROR_TAGS = List.of(Tag.of("type", "failed"));
    private static final List<Tag> KAFKA_ERROR_TAGS = List.of(Tag.of("topic", deduplicationTopicName),
            Tag.of("action", "send"), Tag.of("result", "failure"));

    @Value("${kafka.topic.deduplication}")
    private String deduplicationTopicName; 
   
    public DeduplicationErrorMetric() {
        super(Map.of(
                DEDUPLICATIONS_METRIC, DEDUPLICATION_ERROR_TAGS,
                KAFKA_MESSAGES_METRIC, KAFKA_ERROR_TAGS
        ));
    }

    @Override
    public void incrementMetric(String key) {
        errorCounters.get(key).increment();
    }
}
hassan
  • 11
  • 2
0

Remove the keyword "static" and then you will be able to change it in the instance.

Static means that the field is locked to the class.

public class DeduplicationErrorMetric extends AbstractErrorMetric {
    
    public static final String DEDUPLICATIONS_METRIC = "deduplications";
    public static final String KAFKA_MESSAGES_METRIC = "kafka.messages";
    
    private String DEDUPLICATION_TOPIC_NAME;
    
    private static final List<Tag> DEDUPLICATION_ERROR_TAGS = List.of(Tag.of("type", "failed"));
    private List<Tag> KAFKA_ERROR_TAGS = List.of(Tag.of("topic", DEDUPLICATION_TOPIC_NAME),
            Tag.of("action", "send"), Tag.of("result", "failure"));
    
    public DeduplicationErrorMetric() {
        super(Map.of(
                DEDUPLICATIONS_METRIC, DEDUPLICATION_ERROR_TAGS,
                KAFKA_MESSAGES_METRIC, KAFKA_ERROR_TAGS
        ));
    }
    
    @Override
    public void incrementMetric(String key) {
        errorCounters.get(key).increment();
    }
    
    public void setTopic(String value){
        DEDUPLICATION_TOPIC_NAME = value;   
    }
}

private void example(){
    DeduplicationErrorMetric dem = new DeduplicationErrorMetric();
    
    //Set the instance value directly
    dem.DEDUPLICATION_TOPIC_NAME = "Test";
    
    //Set via a function, potentially with other variables. 
    demo.setTopic("Test");
}

I would also recommend making the variable name lowercase now that it is not static, as good coding practice.

James
  • 620
  • 3
  • 13