some help needed with fixing circular dependencies

hey guys. can smb help me out with fixing circular dependencies?
The dependencies of some of the beans in the application context form a cycle:

infoRestController
┌─────┐
| BGWService defined in file
↑ ↓
| importService defined in file
└─────┘
The dependencies of some of the beans in the application context form a cycle:

infoRestController
┌─────┐
| BGWService defined in file
↑ ↓
| importService defined in file
└─────┘
This error doesnt even make sense, wtf?
18 Replies
JavaBot
JavaBot5mo ago
This post has been reserved for your question.
Hey @bambyzas! Please use /close or the Close Post button above when your problem is solved. Please remember to follow the help guidelines. This post will be automatically closed after 300 minutes of inactivity.
TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.
tjoener
tjoener5mo ago
Well, make either importservice not depend on bgwservice or the other way around
bambyzas
bambyzasOP5mo ago
um, yeah. but the thing is that i need both of them to depend on each other
tjoener
tjoener5mo ago
There's a workaround, if you annotate a non-final field with @AutoWired instead of the constructor But circular dependencies are a sign that there's something wrong with your classes They shouldn't depend on each other
bambyzas
bambyzasOP5mo ago
@Service
@Slf4j
public class BGWService {

ImportService importService;
CustomerRepository customerRepository;
AppConfig appConfig;
XmlUtil xmlUtil;
PaymentRepository paymentRepository;

public BGWService(AppConfig appConfig, XmlUtil xmlUtil, CustomerRepository customerRepository, PaymentRepository paymentRepository, ImportService importService) {
this.appConfig = appConfig;
this.xmlUtil = xmlUtil;
this.customerRepository = customerRepository;
this.paymentRepository = paymentRepository;
this.importService = importService;
}
public void createPaymentpaymentConfirmation(PaymentDTO paymentConfirmationRequest) throws NoEarlierPaymentException, JAXBException, IOException {
log.info("BGWService.createPaymentpaymentConfirmation");

Optional<Payment> earlierPayment=paymentRepository.findByTransactionIdAndAmount(paymentConfirmationRequest.getTransactionId(), paymentConfirmationRequest.getAmount());
if (earlierPayment.isEmpty()) {
log.info("BGWService.createPaymentConfirmation.NoEarlierPaymentException.TransactionId:{}.Amount:{}",paymentConfirmationRequest.getTransactionId(),paymentConfirmationRequest.getAmount());

throw new NoEarlierPaymentException("No earlier payment with transactionId:"+paymentConfirmationRequest.getTransactionId()+" and amount:"+paymentConfirmationRequest.getAmount());
}

Payment payment=PaymentMapper.toEntity(paymentConfirmationRequest);
importService.importStatement(appConfig.getSystemUserId());
paymentRepository.save(payment);
}
}
@Service
@Slf4j
public class BGWService {

ImportService importService;
CustomerRepository customerRepository;
AppConfig appConfig;
XmlUtil xmlUtil;
PaymentRepository paymentRepository;

public BGWService(AppConfig appConfig, XmlUtil xmlUtil, CustomerRepository customerRepository, PaymentRepository paymentRepository, ImportService importService) {
this.appConfig = appConfig;
this.xmlUtil = xmlUtil;
this.customerRepository = customerRepository;
this.paymentRepository = paymentRepository;
this.importService = importService;
}
public void createPaymentpaymentConfirmation(PaymentDTO paymentConfirmationRequest) throws NoEarlierPaymentException, JAXBException, IOException {
log.info("BGWService.createPaymentpaymentConfirmation");

Optional<Payment> earlierPayment=paymentRepository.findByTransactionIdAndAmount(paymentConfirmationRequest.getTransactionId(), paymentConfirmationRequest.getAmount());
if (earlierPayment.isEmpty()) {
log.info("BGWService.createPaymentConfirmation.NoEarlierPaymentException.TransactionId:{}.Amount:{}",paymentConfirmationRequest.getTransactionId(),paymentConfirmationRequest.getAmount());

throw new NoEarlierPaymentException("No earlier payment with transactionId:"+paymentConfirmationRequest.getTransactionId()+" and amount:"+paymentConfirmationRequest.getAmount());
}

Payment payment=PaymentMapper.toEntity(paymentConfirmationRequest);
importService.importStatement(appConfig.getSystemUserId());
paymentRepository.save(payment);
}
}
public class ImportService {

LmsService lmsService;
XmlUtil xmlUtil;
BGWService bgwService;
AppConfig appConfig;

@Autowired
DivisionRepository divisionRepository;

@Autowired
CashRegRepository cashRegRepository;

@Autowired
CustomerIDResolverService customerIDResolverService;

@Autowired
BankAccountConfig bankAccountConfig;

DateTimeFormatter formatterCurrent = DateTimeFormatter.ofPattern("yyyyMMdd");
DateTimeFormatter formatterEod = DateTimeFormatter.ofPattern("yyyyMMdd");

//constructor


private String generateFileName(String type, DateTimeFormatter formatter, LocalDateTime date) {
return type + date.format(formatter) + ".xml";
}

public void importSbankStatement(Long userId) throws JAXBException, IOException {
log.info("importSbankStatement started");
for (BankAccount bankAccount : bankAccountConfig.getSbankBankAccounts()) {
log.info("iban: " + bankAccount.getIban());
ResponseEntity<String> accountStatementResponse = bgwService.getAccountStatementResponse();
if (accountStatementResponse.getStatusCode().value() == 200) {
HttpHeaders accountStatementResponseHeaders = accountStatementResponse.getHeaders();
String xTrackingId = accountStatementResponseHeaders.get("X-Tracking-ID").get(0);
bgwService.deleteAccountStatement(xTrackingId);

String xmlStr = accountStatementResponse.getBody();
importFromString(xmlStr, "BGW_C_", userId, bankAccount.getCashRegId());
}
}
log.info("importSbankStatement end");
}
}
public class ImportService {

LmsService lmsService;
XmlUtil xmlUtil;
BGWService bgwService;
AppConfig appConfig;

@Autowired
DivisionRepository divisionRepository;

@Autowired
CashRegRepository cashRegRepository;

@Autowired
CustomerIDResolverService customerIDResolverService;

@Autowired
BankAccountConfig bankAccountConfig;

DateTimeFormatter formatterCurrent = DateTimeFormatter.ofPattern("yyyyMMdd");
DateTimeFormatter formatterEod = DateTimeFormatter.ofPattern("yyyyMMdd");

//constructor


private String generateFileName(String type, DateTimeFormatter formatter, LocalDateTime date) {
return type + date.format(formatter) + ".xml";
}

public void importSbankStatement(Long userId) throws JAXBException, IOException {
log.info("importSbankStatement started");
for (BankAccount bankAccount : bankAccountConfig.getSbankBankAccounts()) {
log.info("iban: " + bankAccount.getIban());
ResponseEntity<String> accountStatementResponse = bgwService.getAccountStatementResponse();
if (accountStatementResponse.getStatusCode().value() == 200) {
HttpHeaders accountStatementResponseHeaders = accountStatementResponse.getHeaders();
String xTrackingId = accountStatementResponseHeaders.get("X-Tracking-ID").get(0);
bgwService.deleteAccountStatement(xTrackingId);

String xmlStr = accountStatementResponse.getBody();
importFromString(xmlStr, "BGW_C_", userId, bankAccount.getCashRegId());
}
}
log.info("importSbankStatement end");
}
}
i removed some code, bc i needed to hide some sensitive stuff but u can still see the logic and the dependency between these two services
tjoener
tjoener5mo ago
What does BGW mean?
bambyzas
bambyzasOP5mo ago
no idea 😦
tjoener
tjoener5mo ago
I see a call to bgwService.deleteAccountStatement MAybe that should be in a different service that manages statements? So you wouldn't have to call bgwservice? This is application architecture and hard to tell with bits of code I'd have to take a few hours, look at how it works and come up with a plan
bambyzas
bambyzasOP5mo ago
yeah, i know. thanks for at least taking a look haha
JavaBot
JavaBot5mo ago
If you are finished with your post, please close it. If you are not, please ignore this message. Note that you will not be able to send further messages here after this post have been closed but you will be able to create new posts.
tjoener
tjoener5mo ago
The fact that BGWService has both a customerRepository and a paymentRepository screams bad design to me
bambyzas
bambyzasOP5mo ago
but basically id need to redesign the services and how they depend on each other, right?
tjoener
tjoener5mo ago
Big red flags right there Usually you have services depend on one single repository, for the type that they're responsible for
bambyzas
bambyzasOP5mo ago
why? because one service manages two repos?
tjoener
tjoener5mo ago
And if they need to do anything else they need to go through another service yeah, and not even related ones bgwService.deleteAccountStatement does that call any of those repositories?
bambyzas
bambyzasOP5mo ago
nope. just does http req
tjoener
tjoener5mo ago
ok, other angle createPaymentpaymentConfirmation Why isn't that in a PaymentService? And just depend on the PaymentService instead of the BGWService? It's stuff like that, ask if it really belongs there
JavaBot
JavaBot5mo ago
💤 Post marked as dormant
This post has been inactive for over 300 minutes, thus, it has been archived. If your question was not answered yet, feel free to re-open this post or create a new one. In case your post is not getting any attention, you can try to use /help ping. Warning: abusing this will result in moderative actions taken against you.
Want results from more Discord servers?
Add your server