Bean Instantiation Order?

I have the following:

@Service(DropboxService.NAME)
public class DropboxServiceBean implements DropboxService {

    @Inject
    private CustomConfig customConfig;


    private final String ACCESS_TOKEN = customConfig.getDropboxAppToken();
    DbxRequestConfig config = new DbxRequestConfig("dropbox/java-tutorial", "en_US");
    DbxClientV2 client = new DbxClientV2(config, ACCESS_TOKEN);

Does anyone know how I can get the values of the “customConfig.getDropboxAppToken();” to load first. I keep getting the following error:

CustomConfig is an extension of the Config (public interface CustomConfig extends Config )

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘myApp_DropboxService’ defined in URL [jar:file:/E:/Cuba/myApp/deploy/tomcat/webapps/app-core/WEB-INF/lib/app-core-0.1-SNAPSHOT.jar!/com/daryn/myApp/service/DropboxServiceBean.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.daryn.myapp.service.DropboxServiceBean]: Constructor threw exception; nested exception is java.lang.NullPointerException

Hello,

an injection is performed after an object creation, so your CustomConfig has not injected yet when you are assigning a value to the final field.

I suggest that you use the @PostConstruct annotation to do what you want when CustomConfig is injected or use the constructor dependency injection ability.

Best regards,
Daniil.

I tried the @PostConstruct

For some reason the CustomConfig bean is null at PostConstruct. CustomConfig extends Config (so I can have custom properties in the Admin -> Application Properties area of the web app.

What do you mean by “constructor dependency injection ability”.

My workaround (which is not ideal) is the following:

@Service(DropboxService.NAME)
public class DropboxServiceBean implements DropboxService {



    @Inject
    private CustomConfig customConfig;


    private String ACCESS_TOKEN = "";
    DbxRequestConfig config =new DbxRequestConfig("dropbox/java-tutorial", "en_US");
    DbxClientV2 client;

    public static boolean isInitiated = false;

    public void generateDbxClient(){
        ACCESS_TOKEN = customConfig.getDropboxAppToken();
        client = new DbxClientV2(config, ACCESS_TOKEN);
    }

    @Override
    @Transactional
    public void uploadFile(FileDescriptorExt file, String path) {

        if(isInitiated==false){
            generateDbxClient();
            isInitiated=true;
        }

Any suggestions appreciated.

To use constructor injection you should add a parameter to constructor and mark it by the @Autowired annotation:

@Service(MyAwesomeService.NAME)
public class MyAwesomeServiceBean implements MyAwesomeService {

    private final String configValue;

    @Autowired
    public MyAwesomeServiceBean(MyConfig myConfig) {
        configValue = myConfig.getSomeConfigValue();
    }

    @Override
    public String doSomethingUseful() {
        return configValue;
    }
}

Also, I’ve prepared an example for you. Please take a look at the project in attachments.
Best regards,
Daniil

injecting-config-to-service.zip (315.3K)

The zip you sent doesn’t load

cuba

The 6.6.3 version of CUBA.platform is used in the attached project.

Please update or download a new version of CUBA Studio and try to reopen the project.

Hi Daniil.
This sort-of works. However I was hoping that the values could be set through the web interface @ Administration -> Application Properties.
It only shows up in there if

@Source(type = SourceType.DATABASE)

and not

@Source(type = SourceType.APP) 

When it is SourceType.APP the values cannot be changed in the web client admin area.
And if I change it to SourceType.DATABASE it gives the following error:
Error creating bean with name ‘injectingconfigtoservice_MyAwesomeService’ defined in URL [jar:file:/E:/Cuba/injecting-config-to-service/deploy/tomcat/webapps/app-core/WEB-INF/lib/app-core-0.1-SNAPSHOT.jar!/com/company/injectingconfigtoservice/service/MyAwesomeServiceBean.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.company.injectingconfigtoservice.service.MyAwesomeServiceBean]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:279)

Untitled

Hello,
it happens because AppContext is not ready at this moment.
You should subscribe for AppContext events and obtain your config value when the context is initialized:

@Service(MyAwesomeService.NAME)
public class MyAwesomeServiceBean implements MyAwesomeService, AppContext.Listener {

    protected String configValue;

    @Override
    public String doSomethingUseful() {
        return configValue;
    }

    @PostConstruct
    public void init() {
        AppContext.addListener(this);
    }

    @Override
    public void applicationStarted() {
        configValue = AppBeans.get(Configuration.class)
                .getConfig(MyConfig.class)
                .getSomeConfigValue();
    }

    @Override
    public void applicationStopped() {
        // do what you want
    }
}

You can find more information in the documentation: link

Best regards,
Daniil.