0

I'm using 2 common packages, Immutables and Guice. The very first thing that happens at runtime is I load setting from environment and other sources into settings into a singleton, non-Immutable config class, let's call it MyConfig, that for example, exposes a public getSettingX() method.

 MyConfig myConfig = MyConfig.intialize().create();  
 String settingX = myConfig.getSettingX();

I have one abstract Immutable class, call it AbstractImmutable. that at instantiation needs to set a field based on the myConfig.getSettingX().

@Value.Immutable
abstract class AbstractImmutable {
   abstract String getSettingX(); // Ideally set 
}

Now, typically I inject MyConfig into classes using Guice, and would liket to figure a way to do this for implementations of the AbstractImmutable class (to avoid manually having to inject the MyConfig class every time I build an object--whole reason using juice to begin with, to manage my DI). However, since the concrete Immutables classes are generated at compile, it doesn't to work with the usual Guice injection annotations.

There's indication on the Immutables site of using the builder package to annotate a static factory method, but I can't seem to figure how to add this to the abstract immutable class.

Anyone have any suggestions?

Ray
  • 40,256
  • 21
  • 101
  • 138
  • sounds like a bad design to me, what do you need it for? Do you need snapshots of your config for some reasons? – Krzysztof Cichocki Jul 26 '17 at 08:58
  • Initializing an immutable by injecting in it's dependency is a bad design? – Ray Jul 26 '17 at 09:02
  • 1
    Not that, but the abstract class `AbstractImmutable` is meaningless for me, who and for what reason will extend it, what this class is for? This makes me confused what this code should do, what it is used for? I have no idea... and because of that it is bad design. – Krzysztof Cichocki Jul 26 '17 at 09:42
  • 1
    It's just a name for the example, call it `AbstractCarrot` instead if you prefer. The Immutables library would createsa concreate `Carrot` class at compile time based on the `AbstractCarrot` class as long as it is annotateed as `@Immutable`. You don't extend it, Immutables does, check the link in the question to learn how the Immutables library works. You'd use a `Carrot` class if you were a `Bunny` class for example – Ray Jul 26 '17 at 09:47
  • I know that, but still it doesn't make sense to me... as to your problem just create a constructor in `AbstractImmutable` that takes `MyConfig` and mark this constructor with `@Inject` – Krzysztof Cichocki Jul 26 '17 at 09:54
  • @KrzysztofCichocki sure, but how does this constructor get called by immutables when you say call an internal builder class: `Carrot.builder().build()` – Ray Jul 26 '17 at 16:35
  • So make also a private parameterless constructor to be used by immutables. – Krzysztof Cichocki Jul 27 '17 at 06:37
  • @KrzysztofCichocki the Immutables library already makes a empty constructror for you, but now we're back to not having dependencies auto injected into the creation of the Immutables – Ray Jul 27 '17 at 07:20
  • You need to have two constructors, one parameterless, and one with @Inject, then when you will get the bean from the context, guice will inject this dependency – Krzysztof Cichocki Jul 27 '17 at 07:23
  • @KrzysztofCichocki I think I follow, could you put a basic example of this in a answer and I'll try it out and mark it correct if I get it to work :) – Ray Jul 27 '17 at 14:28

1 Answers1

1

To my knowledge, there is no way to do this on the generated Immutables class itself (though there may be some funny stuff you could do with @InjectAnnotation), so you may be out of luck there.

Even though you are asking under the guise of Guice, what you are asking for reminds me of the pattern that AutoFactory uses, and should be similarly applicable. In essence, take advantage of the Factory Pattern by injecting into the factory and then the factory will create the Immutable object.

For example, specifically referring to your case,

@Value.Immutable
abstract class ValueObject {
    MyConfig getMyConfig();

    @Value.Derived
    String getSettingX() {
        getMyConfig().getSettingX();
    }

    String getAnotherProperty();

    class ValueObjectFactory {
        @Inject MyConfig myConfig;

        ValueObject create(String anotherProperty) {
            return ImmutableValueObject.builder()
                .setMyConfig(this.myConfig)
                .setAnotherProperty(anotherProperty)
                .build();
        }
    }
}

Then, in the application code, you would inject the ValueObjectFactory directly and call create on it as

class SomeApplicationClass {
    @Inject ValueObjectFactory factory;

    void someMethod() {
        ValueObject = factory.create("myString");

        // ... do something with the ValueObject
    }
}

Similarly, you could define your factory as a builder, but that will be a decision you will have to make based on the number of parameters you have.