12

Instead of using Properties inside the constructor I saw @Value annotation should do the trick.

It works in another implementation that I have but here it doesn't

Controller:

@Autowired
private Customer customer;

My Class

@Service
public class Customer {

    /** The soap GW endpoint. */
    @Value("${soapGWEndpoint}")
    private String soapGWEndpoint;

    /** The soap GW app name. */
    @Value("${soapGWApplName}")
    private String soapGWAppName;

    /** The soap GW user. */
    @Value("${generic.user}")
    private String soapGWUser;

    /** The soap GW password. */
    @Value("${generic.user.password}")
    private String soapGWPassword;

    public Customer () {
        // All parameters are null:
        login(soapGWEndpoint, soapGWAppName, soapGWUser, soapGWPassword);
    }
}

But they are on the application.properties file.

Why in this occasion I cannot use @Value?

deHaar
  • 17,687
  • 10
  • 38
  • 51
user10867569
  • 157
  • 2
  • 6

4 Answers4

19

Spring won't inject the preoperties' values until the object is fully instantiated (The first thing that Spring will do is call your constructor, since its the default way to create a new object). You should call login() in a @PostConstruct method so Spring calls it automatically after initializing the object:

@Service
public class Customer {

    /** The soap GW endpoint. */
    @Value("${soapGWEndpoint}")
    private String soapGWEndpoint;

    /** The soap GW app name. */
    @Value("${soapGWApplName}")
    private String soapGWAppName;

    /** The soap GW user. */
    @Value("${generic.user}")
    private String soapGWUser;

    /** The soap GW password. */
    @Value("${generic.user.password}")
    private String soapGWPassword;

    public Customer () {
    }

    @PostConstruct
    public void init() {
      login(soapGWEndpoint, soapGWAppName, soapGWUser, soapGWPassword);
    }
}
gbandres
  • 901
  • 7
  • 14
13

Another option is to use constructor injection like this

@Service
public class Customer {

  private String soapGWEndpoint;
  private String soapGWAppName;
  private String soapGWUser;
  private String soapGWPassword;

  @Autowired
  public Customer(@Value("${soapGWEndpoint}") String soapGWEndpoint,
                @Value("${soapGWApplName}") String soapGWAppName,
                @Value("${generic.user}") String soapGWUser,
                @Value("${generic.user.password}") String soapGWPassword) {
    this.soapGWEndpoint = soapGWEndpoint;
    this.soapGWAppName = soapGWAppName;
    this.soapGWUser = soapGWUser;
    this.soapGWPassword = soapGWPassword;
    login(soapGWEndpoint, soapGWAppName, soapGWUser, soapGWPassword);
  }
}
Ivan
  • 8,508
  • 2
  • 19
  • 30
3

You can use @PostConstruct after the object is initialised. Please, have a look into the sample code that I write earlier:

@Configuration
public class BrinkWebserviceConfig {

    private static final Logger LOG = LoggerFactory.getLogger(BrinkWebserviceConfig.class);

    private String accessToken;
    private String locationToken;
    private String domain;

    @Value("${brink.soap.settingsAPI}")
    String BRINK_SETTINGS_API;

    @Value("${brink.soap.sales2API}")
    String BRINK_SALES2_API;

    @Value("${brink.soap.orderingAPI}")
    String BRINK_ORDERING_API;

    @Value("${brink.soap.settings2API}")
    String BRINK_SETTINGS2_API;

    @PostConstruct
    public void init() {
        LOG.info("Loading the access and location tocken for using in the configuration and setting the clients URLs");

        loadCredentialsAndDomainURL();
        loadClientsAPI();
    }

    public ClientInterceptor brinkHeaderInterceptor(Logger LOG) {

        return new ClientInterceptorAdapter() {
            @Override
            public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
                TransportContext context = TransportContextHolder.getTransportContext();
                HttpUrlConnection connection = (HttpUrlConnection) context.getConnection();
                try {
                    connection.addRequestHeader("AccessToken", accessToken);
                    connection.addRequestHeader("LocationToken", locationToken);
                } catch (IOException e) {
                    LOG.error("header interceptor error", e);
                    return false;
                }

                return true;
            }
        };
    }

    private void loadCredentialsAndDomainURL() {

        String s = "src/test/resources/brink.properties";
        Resource r = new FileSystemResource(s);

        Properties props = new Properties();

        try {
            props.load(r.getInputStream());

//            accessToken = props.getProperty("token");
//            locationToken = props.getProperty("appId");

            accessToken = props.getProperty("password");
            locationToken = props.getProperty("username");
            domain = props.getProperty("domain1");

        } catch (IOException e) {
            LOG.error("We have an error for reading the access and location tokens for Brink web-service config");
        }
    }

    private void loadClientsAPI() {

        BRINK_SETTINGS_API = domain + BRINK_SETTINGS_API;
        BRINK_SALES2_API = domain + BRINK_SALES2_API;
        BRINK_ORDERING_API = domain + BRINK_ORDERING_API;
        BRINK_SETTINGS2_API = domain + BRINK_SETTINGS2_API;
    }
}

At the time of calling loadCredentialsAndDomainURL()`` andloadClientsAPI()methods, the object is ready and can read the property values from theapplication.properties``` file.

Arefe
  • 11,321
  • 18
  • 114
  • 168
0

the issue is as soon as the object is initialized it is throwing null pointer exception

dj11
  • 1
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – hossein Jul 27 '23 at 11:02