0

I'm building a very simple application where multiple services are interacting with eachs others (simulating ATM).

A card service calls a fraud service to check whether or not the card is fraudulent.

I have a problem where I'm retrieving a property from application.properties but it's always returning null and can't figure out why. Here is the code for my Card service.

The Controller

package com.grafana.atm.cardservice.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;

import com.grafana.atm.cardservice.client.FraudServiceClient;
import com.grafana.atm.cardservice.model.Card;

import reactor.core.publisher.Mono;

@RestController
public class CardController {
    Logger logger = LoggerFactory.getLogger(CardController.class);
    FraudServiceClient fraudServiceClient = new FraudServiceClient();

    @PostMapping("/card:check")
    public String checkCardValidity(@RequestBody Card card) {
        logger.info("Checking if the credit card with number "+card.getCardNumber()+" is valid.");

        if (isValidCreditCardNumber(card.getCardNumber())) {
            logger.info("The credit card with number '"+card.getCardNumber()+"' is valid.");

            fraudServiceClient.getFraudServiceClient().post()
            .uri("/fraud:check")
            .body(Mono.just(card), Card.class)
            .retrieve()
            .onStatus(HttpStatus.INTERNAL_SERVER_ERROR::equals,
                response -> response.bodyToMono(String.class).map(Exception::new))
                .bodyToMono(String.class)
            .block();
        } else {
            logger.error("The credit card with number '"+card.getCardNumber()+"' is invalid or cannot be verified.");

            throw new ResponseStatusException(
                HttpStatus.INTERNAL_SERVER_ERROR, "The card number is invalid or cannot be verified.");
        }

        return "all good";
    }
}

The class for the WebClient

package com.grafana.atm.cardservice.client;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;

@Service
public class FraudServiceClient {
    @Value("${atm.application.service.fraud.endpoint}")
    private String fraudServiceEndpoint;

    private final WebClient fraudServiceClient;
    Logger logger = LoggerFactory.getLogger(FraudServiceClient.class);
    
    public FraudServiceClient() {
        logger.info("Creating WebClient for calling the Fraud service at "+fraudServiceEndpoint);

        this.fraudServiceClient = WebClient.builder()
            .baseUrl(fraudServiceEndpoint)
            .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) 
            .build();
    }

    public WebClient getFraudServiceClient() {
        return fraudServiceClient;
    }
}

The Card model

package com.grafana.atm.cardservice.model;

public class Card {
    private String cardNumber;
    private Integer cardExpiryDate;
    private Integer cardCvc;

    public Card() {
    }

    public Card(String cardNumber, Integer cardExpiryDate, Integer cardCvc) {
        this.cardNumber = cardNumber;
        this.cardExpiryDate = cardExpiryDate;
        this.cardCvc = cardCvc;
    }

    public String getCardNumber() {
        return this.cardNumber;
    }

    public Integer getCardExpiryDate() {
        return this.cardExpiryDate;
    }

    public Integer getCardCvc() {
        return this.cardCvc;
    }
}

I confirm the env variable called in my application.properties files is correctly set

Disclamer: I'm very new with Spring Boot - have read a lot but still learning a lot too so pardon me if it sounds obvious :).

application.propertie

spring.application.name=card-service
server.port=${ATM_CARD_SVC_PORT}
atm.application.service.fraud.endpoint=${ATM_FRAUD_SVC_ENDPOINT}
management.endpoint.chaosmonkey.enabled=true
management.endpoint.chaosmonkeyjmx.enabled=true
management.endpoints.web.exposure.include=health,info,prometheus,chaosmonkey
server.error.include-stacktrace=never
server.error.include-message=always

logging.pattern.console=Timestamp=%d{yyyy-MM-dd HH:mm:ss} Level=%p Logger=%logger{36} Message=%msg TraceId=%mdc{trace_id} SpanId=%mdc{span_id} TraceFlags=%mdc{trace_flags} %n
M. Deinum
  • 115,695
  • 22
  • 220
  • 224
Cyrillou
  • 151
  • 1
  • 15
  • Could it be that your env variable called `ATM_FRAUD_SVC_ENDPOINT` is not set? – grekier Apr 24 '23 at 08:36
  • It isn't `null` you are accessing it too early. The value isn't set in the constructor, but afterwards. How would SPring be able to inject a value in an object that hasn't been constructed. – M. Deinum Apr 24 '23 at 08:48
  • IN addition you aren't even uising a Spring managed instance but are creating one yourself. Marked as duplicate for a question regarding @Autowired, as the same applies to `@Value` as well. – M. Deinum Apr 24 '23 at 09:11

0 Answers0