简体   繁体   中英

How to set a default value to variables in Guice

Like we do the following in Spring

@Value("${varName:0}")
int varName;

Is there a way to do this using Google Guice?

In Guice you would annotate the method and make it optional. You then just assign the default value. If no property is there to be injected, it will be the default value.

For example:

public class TestModule3 extends AbstractModule {

    @Override
    protected void configure() {

//      Properties p = new Properties();
//      p.setProperty("myValue", "12");
//      Names.bindProperties(binder(), p); // this binds the properties that usually come for a file

        bind(Manager.class).to(ManagerImpl.class).in(Singleton.class);
    }

    public static interface Manager {
        public void talk();
    }

    public static class ManagerImpl implements Manager {

        @Inject(optional = true)
        @Named("myValue")
        int test = 0;

        @Override
        public void talk() {
            System.out.println(test);
        }
    }

    public static void main(String[] args) {

        Manager instance = Guice.createInjector(new TestModule3()).getInstance(Manager.class);
        instance.talk();

    }
}

This will print "0" for you, because I commented out the property binding. If you remove the comments, it will bind the value 12 to the String myValue. The inject annotation takes care of the rest.

Hope that helps,

EDIT:

As @TavianBarnes pointed out, Guice 4+ has an OptionalBinder. I tried this for your usecase and could not make it work out of the box.

It appears that OptionalBinding is very useful for classes (actual instances), not for properties. Here is why:

  1. You have to know all the properties in advance and bind them to their defaults. It is easy to forget them. The example shown by OP also shows that he does not know if he has the property available (based on the name).

  2. Default implementation of property bindings don't work in combo with the OptionalBinding.

So the way you can make that work is like this:

        OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, Names.named("myValue"))).setDefault()
                .toInstance("777");

        Properties p = new Properties();
        p.setProperty("myValue", "12");

        // use enumeration to include the default properties
        for (Enumeration<?> e = p.propertyNames(); e.hasMoreElements();) {
            String propertyName = (String) e.nextElement();
            String value = p.getProperty(propertyName);

            OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, Names.named(propertyName))).setBinding()
                    .toInstance(value);

        }

I had to copy the Named binding code and change it to support optional bindings.

In summary:

  1. I would prefer to use the optional=true flag + default value in code for properties.

  2. Use the OptionalBinding for actual classes that can be optional.

Finally, there is one more thing you could do - this is my solution in my code. I have a similar requirement (not the optional, but default values).

I want:

  1. Bind my properties
  2. Check if my properties are a variable
  3. Replace the variable
  4. If the variable is not available set a default

Apache offers a handy library for this already which I reuse. This is how my properties look like:

myProperty=${ENV_VAR_NAME:-600}

This is the default annotation of how to define a default value. The above property says:

  1. Use the evnironment variable "ENV_VAR_NAME".
  2. If "ENV_VAR_NAME" is not set, use the value "600"

Then I bind it as follows:

        InputStream resourceAsStream = getClass().getResourceAsStream(path);
        if(resourceAsStream == null) {
            throw new IllegalArgumentException("No property file found for path: " + path);
        }
        try {
            p.load(resourceAsStream);
            EnvironmentVariableSubstitutor envSubstitutor = new EnvironmentVariableSubstitutor(false);
            Set<Object> keys = p.keySet();
            for(Object k : keys) {
                String property = p.getProperty(k.toString());
                property = envSubstitutor.replace(property);
                p.put(k, property);
            }

        } catch (IOException e) {
            throw new IllegalStateException("Could not load properties", e);
        } finally {
            try {
                resourceAsStream.close();
            } catch (IOException e) {
                log.error("Could not close stream for resource " + path);
            }
        }

        Names.bindProperties(binder(), p);

What this code does is:

  1. Load the properties from a resource file
  2. Use the EnvironmentVariableSubstitutor to process the values of the properties and overwrite the result. (see loop)
  3. finally, bind the modified properties to their names.

These are all the solutions I can come up with at short notice :) let me know if something's unclear

Edit 2:

there is some info on OptionalBindings and properties + how to handle default values in this google thread as well: https://groups.google.com/forum/#!topic/google-guice/7Ga79iU_sb0

Artur

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM