Not able to autowire in Abstract class in Mapstruct - spring

I need to autowire my GdsClientHandler I have tried autowiring through constructor, setter methods but still it returns to be null.
#Mapper(componentModel = "spring")
public abstract class SaveHistoryBOToEntityMapper {
#Autowired
private GdsClientHandler gdsClientHandler;
public Set<String> getCityName(final Set<Long> cityIdList, final String countryCode) {
Set<String> cityList = new HashSet<String>();
if(cityIdList.isEmpty() || countryCode==null)
{
return cityList;
}
else
{ cityList = cityIdList.stream().map(cityId -> this.gdsClientHandler.findCityByCountryCode(countryCode, cityId).getCityName()).collect(Collectors.toSet());
return cityList;}
}

Related

Builder Pattern and Dependecy Injection - how to fix problem

I wanted to create a class based on the builder pattern. Using the static method build. Which would return a properly built object based on initial validation checking whether a given object exists in the database.
#Component
#Data
#Builder
public class GetBookedSeatsRequest {
#Autowired
private MovieRepository movieRepository;
#Autowired
public CinemaRepository cinemaRepository;
#Autowired
public PropertiesMovieRepository propertiesMovieRepository;
private String cinemaName;
private String movieName;
private String movieRoom;
#JsonFormat(pattern="yyyy-MM-dd; HH:mm:ss",shape = JsonFormat.Shape.STRING)
private LocalDateTime localDateTime;
private List<Integer> wantedSeats;
public GetBookedSeatsRequest build(ReservationModel reservationModel) throws CinemaNotFoundException, MovieNotFoundException, PropertyMovieNotFoundException {
boolean cinemaExist = cinemaRepository.existsByCinemaName(reservationModel.getCinemaName());
if (!cinemaExist) {
throw new CinemaNotFoundException("Cinema doesn't exist");
}
boolean movieExist = movieRepository.existsByMovieName(reservationModel.getMovieName());
if (!movieExist) {
throw new MovieNotFoundException("Movie doesn't exist");
}
boolean roomExist = movieRepository.existsByMovieRoom(reservationModel.getMovieRoom());
if (!roomExist) {
throw new MovieNotFoundException("Movie Romm doesn't exist");
}
boolean existData = propertiesMovieRepository.existsByStartTimeOfTheMovie(reservationModel.getDateAndTime());
if (!existData) {
throw new PropertyMovieNotFoundException("This data doesn't exist");
}
// boolean existSeats = movieRepository.existsBySeating(reservationModel.getSeatsToBooked());
// if (!existSeats) {
// throw new MovieNotFoundException("This seats doesn't exist");
// }
GetBookedSeatsRequest correct = GetBookedSeatsRequest.builder()
.cinemaName(reservationModel.getCinemaName())
.movieName(reservationModel.getMovieName())
.movieRoom(reservationModel.getMovieRoom())
.localDateTime(reservationModel.getDateAndTime())
.wantedSeats(reservationModel.getSeatsToBooked())
.build();
return correct;
}
}
#Data
#AllArgsConstructor
public class ReservationModel {
private String cinemaName;
private String movieName;
private String movieRoom;
#JsonFormat(pattern="yyyy-MM-dd; HH:mm:ss",shape = JsonFormat.Shape.STRING)
private LocalDateTime dateAndTime;
private List<Integer> seatsToBooked;
}
But I still got some erros. What am I doing wrong, I am learing Spring Boot. Thanks for help
Description:
Parameter 3 of constructor in com.cinema.booking.aop.GetBookedSeatsRequest required a bean of type 'java.lang.String' that could not be found.
Action:
Consider defining a bean of type 'java.lang.String' in your configuration.

NullPointerException by testing a Service with mocked JPARepository

I have a ServiceImp where the repository and objectmapper are injected.
When performing the tests I get a nullpointexception.
I believe the Mock is working because when I print the result Candidate createdOne = candidateRepository.save(c1) I get back c1.
#Service
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class CandidateServiceImp implements CandidateService {
private final CandidateRepository candidateRepository;
private final ObjectMapper objectMapper;
#Override
public List<CandidateDto> getAllCandidates() {
List<Candidate> candidateList = candidateRepository.findAll();
return candidateList.stream()
.map(Candidate::convertEntityToDto)
.collect(Collectors.toList());
}
#Override
public String findCandidateByIdNormal(Long id) throws JsonProcessingException {
Candidate foundCandidate = candidateRepository.findById(id).orElseThrow(() -> new CandidateNotFoundException(id));
return objectMapper.writerWithView(CandidateViews.Normal.class).writeValueAsString(foundCandidate.convertEntityToDto());
}
#Override
public String findCandidateByIdHr(Long id) throws JsonProcessingException {
Candidate foundCandidate = candidateRepository.findById(id).orElseThrow(() -> new CandidateNotFoundException(id));
return objectMapper.writerWithView(CandidateViews.Hr.class).writeValueAsString(foundCandidate.convertEntityToDto());
}
#Override
public CandidateDto createCandidate(CandidateDto candidateToCreateDto) {
Candidate candidateToCreate = candidateToCreateDto.convertDtoToEntity();
Candidate createdCandidate = candidateRepository.save(candidateToCreate);
return createdCandidate.convertEntityToDto();
}
And this ist my test:
#ExtendWith(SpringExtension.class)
public class CandidateServiceTest {
#InjectMocks
CandidateServiceImp candidateServiceImp;
#Mock
CandidateRepository candidateRepository;
private CandidateDto c1Dto;
private CandidateDto c2Dto;
private List<CandidateDto> candidateDtoList;
private Candidate c1;
private Candidate c2;
private List<Candidate> candidateList;
#BeforeEach
void setUp() {
c1Dto = new CandidateDto("Peter", "Parker", "pp#gmail.com", 3500L);
c2Dto = new CandidateDto("Mary", "Jane", "mj#gmail.com", 4500L);
candidateDtoList = List.of(c1Dto, c2Dto);
c1 = new Candidate("Peter", "Parker", "pp#gmail.com", 3500L);
c2 = new Candidate("Mary", "Jane", "mj#gmail.com", 4500L);
candidateList = List.of(c1, c2);
}
#Test
public void createCandidateShouldReturnCandidateDto() {
Mockito.doReturn(c1).when(candidateRepository).save(c1);
Candidate createdOne = candidateRepository.save(c1);
System.out.println();
System.out.println(createdOne.convertEntityToDto());
System.out.println();
assertEquals(c1Dto, candidateServiceImp.createCandidate(c1Dto));
}
And this is the message :
java.lang.NullPointerException: Cannot invoke "de.evoila.personalAbteilung.models.Candidate.convertEntityToDto()" because "createdCandidate" is null
Could someone tell me why it is not finding the createdCandidate?Thanks =D
As explained in the comments, one solution would be to add #EqualsAndHashCode to candidate.
I also find other solution :
#Test
public void createCandidateShouldReturnCandidateDto() {
Mockito.when(candidateRepository.save(any(Candidate.class))).thenAnswer(AdditionalAnswers.returnsFirstArg());
assertEquals(c1Dto, candidateServiceImp.createCandidate(c1Dto));
}
I mocked the repository with any(Candidate.class) and it also works.

Sending #Value annotated fields to a DTO layer returns null

I have a class which is composed of 2 different objects :
public class MyClass{
private OptionClass optionClass;
private ConstantClass constantClass;
public DocumentToSignRestRequest(OptionClass optionClass, ConstantClass constantClass) {
this.optionClass= optionClass;
this.constantClass= constantClass;
}
}
My first class is a classic POJO. My second class retrieve values from the application.properties file.
public class ConstantClass {
#Value("${api.url}")
private String hostName;
#Value("${sign.path}")
private String pathStart;
public ConstantClass () {
this.hostName= getHostName();
this.path = getPath();
}
I map MyClass with MyClassDto in order to call a service.
#PostMapping(
value="/sign",
consumes = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE },
produces = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE }
)
public MyClassRest prepareDocument(#RequestBody DocumentToPrepare documentToPrepare) throws Exception {
MyClassRest returnValue = new MyClassRest ();
ModelMapper modelMapper = new ModelMapper();
MyClassDto myClassDto = modelMapper.map(documentToPrepare, MyClassDto .class);
DocumentDto signedDocument = documentService.signDocument(documentDto);
returnValue = modelMapper.map(signedDocument, DocumentRest.class);
return returnValue;
}
My DTO class work fine and retrieve the OptionClass datas, but concerning the second Class, i obtain null as value, while i try to print it out in the service layer.
Your ConstantClass should be a Bean or a Component (as #cassiomolin says in comments)
#Component
public class ConstantClass {
private String hostName;
private String pathStart;
public ConstantClass (#Value("${api.url}") String url, #Value("${sign.path}") String path ) {
this.hostName = url;
this.pathStart = path;
}
// getters...
Then you can easily inject this component in your Controller and use it.
#Controller
public class YourController(){
private ConstantClass constantClass;
public YourController(ConstantClass constantClass){
this.constantClass = constantClass;
}
#PostMapping("...")
public MyClass post(.....){
.....
MyClass myclass = new MyClass(this.constantClass,...)
.....
}
}
note that Spring can autowire #Value and #Component, ... via the constructor; that can be very useful when you do unit-testing

How to Autowire an interface or abstract class without implementation in Spring

I need to Autowire an interface without an implementation, somehow like the
#Repository tag functionality.
#QueryRepository
public interface EddressBookDao {
#ReportQuery
public List<EddressBookDto> loadEddresses(#EqFilter("id") Long id);
}
#Autowired
private EddressBookDao eddressBookDao;
Result result = eddressBookDao.loadEddresses(1L);
I'm thinking of somehow detecting my #QueryRepository Annotation during ClassPathScan and injecting a Proxy of EddressBookDao object on eddressBookDao Autowire.
Right now I am achieving this functionality in a cumbersome way using the following:
#Autowired
public ReportQueryInvocationHandler reportQuery;
private EddressBookDao eddressBookDao;
public EddressBookDao eddressBook(){
if (eddressBookDao == null) eddressBookDao = reportQuery.handle(EddressBookDao.class);
return eddressBookDao;
}
Here is my Handler creating the Proxy:
#Component
public class ReportQueryInvocationHandler implements InvocationHandler {
public <T> T handle(Class<T> clazz){
return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws NoSuchFieldException, IllegalAccessException {
Type returnType = method.getReturnType();
Annotation[][] annotations = method.getParameterAnnotations();
Report report = dao.createReport();
for (int i = 0; i < args.length; i++) {
Object argument = args[i];
Annotation[] annotationList = annotations[i];
if (annotationList.length == 0) continue;
for (Annotation annotation : annotationList) {
Class<? extends Annotation> annotationType = annotation.annotationType();
String path = null;
if (annotationType.equals(EqFilter.class)) {
path = ((EqFilter) annotation).value();
report.equalsFilter(path, argument);
break;
}
}
}
return report.list((Class<?>) returnType);
}
And here is how I'm calling my it:
List<EddressBookDto> addressed = dao.eddressBook().loadEddresses(8305L);
All I want is to avoid writing this code
private EddressBookDao eddressBookDao;
public EddressBookDao eddressBook(){
if (eddressBookDao == null) eddressBookDao = reportQuery.handle(EddressBookDao.class);
return eddressBookDao;
}
And write this instead:
#Autowired
private EddressBookDao eddressBookDao;
Spring Data doesn't autowire interfaces although it might look this way. It registers factories which produce proxies implementing the interface.
To do something similar you have to implement the FactoryBean interface.
See the JavaDoc for details. There are also tutorials available.

Spring boot - setters on session scoped component not working from singleton service - fields are null

I have a simple service behind a REST controller in Spring Boot. The service is a singleton (by default) and I am autowiring a session-scoped bean component used for storing session preferences information and attempting to populate its values from the service. I call setters on the autowired component, but the fields I am setting stay null and aren't changed.
Have tried with and without Lombok on the bean; also with and without implementing Serializable on FooPref; also copying properties from FooPrefs to another DTO and returning it; also injecting via #Autowired as well as constructor injection with #Inject. The fields stay null in all of those cases.
Running Spring Boot (spring-boot-starter-parent) 1.5.6.RELEASE, Java 8, with the spring-boot-starter-web.
Session-scoped component:
#Component
#SessionScope(proxyMode = ScopedProxyMode.TARGET_CLASS)
#Data
#NoArgsConstructor
public class FooPrefs implements Serializable {
private String errorMessage;
private String email;
private String firstName;
private String lastName;
}
REST Controller:
#RestController
#RequestMapping("/api/foo")
public class FooController {
#Autowired
private FooPrefs fooPrefs;
private final FooService fooService;
#Inject
public FooController(FooService fooService) {
this.fooService = fooService;
}
#PostMapping(value = "/prefs", consumes = "application/json", produces = "application/json")
public FooPrefs updatePrefs(#RequestBody Person person) {
fooService.updatePrefs(person);
// These checks are evaluating to true
if (fooPrefs.getEmail() == null) {
LOGGER.error("Email is null!!");
}
if (fooPrefs.getFirstName() == null) {
LOGGER.error("First Name is null!!");
}
if (fooPrefs.getFirstName() == null) {
LOGGER.error("First Name is null!!");
}
return fooPrefs;
}
}
Service:
#Service
#Scope(value = "singleton")
#Transactional(readOnly = true)
public class FooService {
#Autowired
private FooPrefs fooPrefs;
#Inject
public FooService(FooRepository fooRepository) {
this.fooRepository = fooRepository;
}
public void updatePrefs(Person person) {
fooRepository.updatePerson(person);
//the fields below appear to getting set correctly while debugging in the scope of this method call but after method return, all values on fooPrefs are null
fooPrefs.setEmail(person.getEmail());
fooPrefs.setFirstName(person.getFirstName());
fooPrefs.setLastName(person.getLastName());
}
}
I discovered my problem. Fields were being added to my FooPrefs session-managed object and were breaking my client. The setters were actually working and being nulled out by some error handling code.
Edits per below fixed the JSON serialization problems:
Session-scoped component (no change)
New Dto
#Data
#NoArgsConstructor
public class FooPrefsDto {
private String errorMessage;
private String email;
private String firstName;
private String lastName;
}
Controller (updated)
#RestController
#RequestMapping("/api/foo")
public class FooController {
private final FooService fooService;
#Inject
public FooController(FooService fooService) {
this.fooService = fooService;
}
#PostMapping(value = "/prefs", consumes = "application/json", produces = "application/json")
public FooPrefsDto updatePrefs(#RequestBody Person person) {
FooPrefsDto result = fooService.updatePrefs(person);
// results coming back correctly now
if (result.getEmail() == null) {
LOGGER.error("Email is null!!");
}
if (result.getFirstName() == null) {
LOGGER.error("First Name is null!!");
}
if (result.getFirstName() == null) {
LOGGER.error("First Name is null!!");
}
return result;
}
}
Service (updated)
#Service
#Scope(value = "singleton")
#Transactional(readOnly = true)
public class FooService {
#Autowired
private FooPrefs fooPrefs;
#Inject
public FooService(FooRepository fooRepository) {
this.fooRepository = fooRepository;
}
public FooPrefsDto updatePrefs(Person person) {
fooRepository.updatePerson(person);
//the fields below appear to getting set correctly while debugging in the scope of this method call but after method return, all values on fooPrefs are null
fooPrefs.setEmail(person.getEmail());
fooPrefs.setFirstName(person.getFirstName());
fooPrefs.setLastName(person.getLastName());
return getFooPrefsDto();
}
private FooPrefsDto getFooPrefsDto() {
FooPrefsDto retDto = new FooPrefsDto();
retDto.setEmail(fooPrefs.getEmail());
retDto.setLastName(fooPrefs.getLastName());
retDto.setFirstName(fooPrefs.getFirstName());
return retDto;
}
}

Resources