TransWikia.com

Loading properties and injecting to final variables - Java

Stack Overflow Asked by sachin on February 3, 2021

I want to load property values to a constants class.I can do that by injecting the value in class constructor or static initialization like the following.

public class MyConstants {
    public final String CONSTANT;

    Myconstants() {
        //read property and set to this.CONSTANT
    }
}

Above initialization works fine. But problem arises when I have to use the CONSTANT in a switch case statement. It will give me error because CONSTANT at that point is not constant but blank final field.

Is there any way I can read properties file and put value to CONSTANT so that no compilation error exist? [Like loading properties and setting at compile time itself]. I am using spring and is there any Spring or java workaround for this use case. My intention is to not build for each time a constant change. Also How would you approach to this use case?

Thanks

2 Answers

Usually a property file consists of 'key=value' pairs which can be loaded at runtime. Environment variables may be used similarly. In general, the constant is the key and the value is used to impact application logic. As long as the key is unchanged, the property value can be changed as needed without any need to recompile and the range of possible values can be used in a switch statement. Ex:

    public static void main(String[] args)
    {
        AppConfigParam<Type1> type1   = new AppConfigParam<>("Param1", Type1::valueOf);
        AppConfigParam<Integer> type2 = new AppConfigParam<>("Param2", Integer::parseInt);
        switch(type1.value().orElseThrow(() -> new IllegalStateException("Missing type"))) { case A: break; }
        switch(type2.value().orElseThrow(() -> new IllegalStateException("Missing type"))) { case 1: break; }
    }

    public enum Type1{ A, B, C }

    private static final class AppConfigParam<T>
    {
        private final String constant;
        private final Function<? super String, T> resolver;
        AppConfigParam(String constant, Function<? super String, T> resolver){ this.constant = constant; this.resolver = resolver; }
        public Optional<T> value(){ return Optional.ofNullable(PARAMS.get(constant)).map(resolver); }
        private static final Map<String, String> PARAMS = System.getenv();
    }

While it will not be possible to dynamically set constants, it may be possible to use dynamic constants in switch statements by having a 2 phase build process.

  1. Read properties and generate constant classes.
  2. Compile rest of project.

Answered by mike1234569 on February 3, 2021

the strings in switch statements are 'hardcoded'. It is literally impossible to make a switch/case statement in java whose 'case' elements are not locked in at compile time. If you want to load those string 'constants' in during app initialization from a properties file, they aren't constant.

Or at least, as far as the needs of java's string-based switch/case is concerned, not constant

Instead, use a java.util.Map of some sort (that maps string values onto runnables or whatnot representing what you're now putting in case blocks), or a bunch of if/else-if statements.

EDIT: How to use a Map to do this.

@FunctionalInterface
public interface CommandProcessor {
    String apply(String cmd);
}

public class CommandHandler {
    private Map<String, CommandProcessor> processors = Map.of(
        "hello", cmd -> "Hello, " + cmd,
        "time", cmd -> "It is " + System.currentTimeMillis() + " past 1970.",
        "capitalize", String::toUpperCase);

    public static void main(String[] args) throws Exception {
        Scanner s = new Scanner(System.in);
        s.useDelimiter("r?n");
        CommandProcessor unknownCommand =
            cmd -> "Known commands: " + processors.keySet();

        while (true) {
            String line = s.next();
            String[] parts = line.split("\s+", 2);
            var processor = processors.getOrDefault(parts[0], unknownCommand);
            String answer = processor.apply(parts.length > 1 ? parts[1] : "");
            System.out.println(answer);
        }
    }
}

Answered by rzwitserloot on February 3, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP