I'm modifiying the maping on existing software. It uses MapStruct (1.2.0), and Lombok (1.16.18)
Before modification, i have this class:
public class ReservationCreateRSRDTO {
#JsonProperty("reservation_id")
private String reservationId;
}
I need to change it to
#Data
#GenerateCoverage
#NoArgsConstructor
#AllArgsConstructor
#Builder
#JsonInclude(JsonInclude.Include.NON_NULL)
public class ReservationCreateRSRDTO {
#JsonProperty("delivery_slot_reservation")
private DeliverySlotReservation deliverySlotReservation;
}
#Data
#GenerateCoverage
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class DeliverySlotReservation {
#NotBlank
#JsonProperty("identifier")
#Size(min = 13, max = 13)
private String identifier;
}
which is mapped by
#Mapper
public interface ReservationControllerMapper {
ReservationCreateRSRDTO toReservationCreateRSRDTO(ReservationCreateODTO reservationCreateODTO);
}
The source object:
#Data
#GenerateCoverage
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class ReservationCreateODTO {
private String reservationId;
}
I modified the mapping to
#Mappings({
#Mapping(source = "reservationId", target = "deliverySlotReservation.identifier"),
})
ReservationCreateRSRDTO toReservationCreateRSRDTO(ReservationCreateODTO reservationCreateODTO);
But when accesing attribute deliverySlotReservation from ReservationCreateRSRDTO after the mapping, it returns null.
I'm triying to debug in eclipse, into generated classes:
#Override
public ReservationCreateRSRDTO toReservationCreateRSRDTO(ReservationCreateODTO reservationCreateODTO) {
if ( reservationCreateODTO == null ) {
return null;
}
ReservationCreateRSRDTO reservationCreateRSRDTO = new ReservationCreateRSRDTO();
reservationCreateRSRDTO.setDeliverySlotReservation(
reservationCreateODTOToDeliverySlotReservation( reservationCreateODTO ) );
return reservationCreateRSRDTO;
}
protected DeliverySlotReservation reservationCreateODTOToDeliverySlotReservation(ReservationCreateODTO reservationCreateODTO) {
if ( reservationCreateODTO == null ) {
return null;
}
DeliverySlotReservation deliverySlotReservation = new DeliverySlotReservation();
deliverySlotReservation.setIdentifier( reservationCreateODTO.getReservationId() );
return deliverySlotReservation;
}
I call toReservationCreateRSRDTO with a not null ReservationCreateODTO with not noll identifier
but debbuger is not stepping into reservationCreateODTOToDeliverySlotReservation().
No exception es thrown, but toReservationCreateRSRDTO() returns an ReservationCreateRSRDTO object with null 'deliverySlotReservation'
Edit
I workarrounded it with a custom mapping:
#Mapping(source = "reservationId", target = "deliverySlotReservation", qualifiedByName = "toDeliverySlotReservation")
ReservationCreateRSRDTO toReservationCreateRSRDTO(ReservationCreateODTO reservationCreateODTO);
#Named("toOrder")
public static DeliverySlotReservation toDeliverySlotReservation(String identifier) {
return new DeliverySlotReservation(identifier);
}
but still donĀ“t know why it does not work with the normal mapping
Related
I have an interface mapper for profile:
#Mapper(componentModel = "spring", builder = #Builder(disableBuilder = true))
public interface SellerProfileMapper {
#Mapping(target = "companyProfileDTO.companyProfileId", source = "id")
#Mapping(target = "companyProfileDTO.companyPicture", source = "company.picture", qualifiedByName = "buildBase64EncodingProfilePicture")
SellerProfileResponseDTO entityToSellerProfileResponseDTO(SellerProfileV2 sellerProfileV2);
#Named("buildBase64EncodingProfilePicture")
default String buildBase64EncodingProfilePicture(Image picture) {
return ofNullable(picture)
.map(image -> Base64.getEncoder().encodeToString(image.getContent()))
.orElse(null);
}
The problem is that the implementation for this mapper can only work if I remove either
#Mapping(target = "companyProfileDTO.companyProfileId", source = "id")
or this
#Mapping(target = "companyProfileDTO.companyPicture", source = "company.picture", qualifiedByName = "buildBase64EncodingProfilePicture")
then the implementation is generated! The question is why? Did I miss anything?
This is the DTO:
#Data
#Builder
#AllArgsConstructor
public class SellerProfileResponseDTO {
private CompanyProfileDTO companyProfileDTO;
private SellerProfileDTO sellerProfileDTO;
}
#NoArgsConstructor
#AllArgsConstructor
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
#Schema(description = "Being used as a based class for Adviser, Buyer and Seller company profile.")
public class CompanyProfileDTO {
#Schema(description = "Company logo as a base64 img", type = "String")
private String companyPicture;
private String companyPictureFileName;
private String companyProfileId;
private String companyId;
}
this is the entity I want to map:
public class SellerProfileV2 {
private String id;
private String alias;
private Company company;
...
}
The error that I get is:
Internal error in the mapping processor: java.lang.RuntimeException: org.ma pstruct.ap.shaded.freemarker.core.InvalidReferenceException: The following has evaluated to null or missing:
public interface SellerProfileMapper {
^
==> ext.targetBeanName [in template "org/mapstruct/ap/internal/model/assignment/UpdateWrapper.ftl" at line 31, column 12]
----
Tip: It's the step after the last dot that caused this error, not those before it.
----
Tip: If the failing expression is known to be legally refer to something that's null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (Thes
e only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)?
This is the generated class for the mapper:
#Component
public class SellerProfileMapperImpl implements SellerProfileMapper {
#Override
public SellerProfileResponseDTO entityToSellerProfileResponseDTO(SellerProfileV2 sellerProfileV2) {
if ( sellerProfileV2 == null ) {
return null;
}
CompanyProfileDTO companyProfileDTO = null;
CompanyProfileDTO companyProfileDTO = null;
if ( sellerProfileV2.getCompany() != null ) {
if ( FreeMarker template error:
The following has evaluated to null or missing:
==> ext.targetBeanName [in template "org/mapstruct/ap/internal/model/assignment/UpdateWrapper.ftl" at line 31, column 12]
----
Tip: It's the step after the last dot that caused this error, not those before it.
I have a simple document:
#Document
#NoArgsConstructor
#AllArgsConstructor
#Builder
#ToString
public class ProductUnit {
#Id
String id;
private String name;
private Integer price;
private LocalDateTime localDateTime;
}
Simple MongoRepository :
public interface productRepo extends MongoRepository<ProductUnit,String> {
ProductUnit deleteByName(String name);
List<ProductUnit> findByPrice(Integer price);
}
and Service :
#Service
public class productServiseImpl implements productServise {
#Autowired
productRepo repository;
#Override
public ProductUnit saveOrUpdate(ProductUnit productUnit) {
System.out.println("inside save or update");
return repository.save(productUnit);
}
#Override
public List<ProductUnit> findAll() {
return repository.findAll();
}
#Override
public ProductUnit deleteUnitByPrice(String name) {
return repository.deleteByName(name);
}
#Override
public List<ProductUnit> findByPrice(Integer price) {
return repository.findByPrice(price);
}
}
Now , inside RestController , I pass id through a post request and use a random class to generate a random value of the price and name .At this stage everything is fine, i.e. all values were initialized correctly, but when it comes to service.saveOrUpdate(forSave) It stores the value incorrectly, i.e. the request returns an empty json and the findAll method returns a list of empty json.Can you tell me what the error is? thanks
#RestController
public class productUnitRestController {
#Autowired
productServise service;
#Autowired
Supplier<MetaInfGenerator> generatorSupplier;
#GetMapping(path = "/all")
public List<ProductUnit> getAllProoduct(){
return service.findAll();
}
#PostMapping(path = "/products")
public ProductUnit createProoduct(#RequestParam("id") Optional<String> newId){
System.out.println("***** iside PostMapping ******");
MetaInfGenerator generator = generatorSupplier.get();
System.out.println("***** supplier PostMapping ******");
ProductUnit forSave = ProductUnit.builder()
.id(newId.get())
.name(generator.getRandomString())
.price(generator.getRandomInteger())
.localDateTime(LocalDateTime.now()).build();
System.out.println(forSave);
return service.saveOrUpdate(forSave);
}
}
This is my Data Repository file and i used native query to retrieve all data address(Locations) of Data. I called the function using Postman and I got null outputs of locations. This my first time of using Native query and its really impossible to solve these errors
DataRepository
public interface DataRepository extends JpaRepository<Data, Long> {
#Query(value = "SELECT dataAddress FROM Data")
List<DataProject> getDataAddress();
}
DataServiceImpl
public List<DataProject> getDataAddress() {
return dataRepository.getDataAddress();
}
DataService
List<DataProject> getDataAddress();
DataModel
#Entity
#Table(name = "CCCData")
public class Data {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long dataId;
#Column(name = "DATA_NAME")
private String dataName;
#Column(name ="DATA_ADDRESS")
private String dataAddress;
#Column(name = "DATA_DESC")
private String dataDesc;
#CreationTimestamp
private Date dateOfCreated;
#CreationTimestamp
private Date dateOfUpdated;
public long getDataId() {
return dataId;
}
public void setDataId(long dataId) {
this.dataId = dataId;
}
public String getDataName() {
return dataName;
}
public void setDataName(String dataName) {
this.dataName = dataName;
}
public String getDataAddress() {
return dataAddress;
}
public void setDataAddress(String dataAddress) {
this.dataAddress = dataAddress;
}
public String getDataDesc() {
return dataDesc;
}
public void setDataDesc(String dataDesc) {
this.dataDesc = dataDesc;
}
public Date getDateOfCreated() {
return dateOfCreated;
}
public void setDateOfCreated(Date dateOfCreated) {
this.dateOfCreated = dateOfCreated;
}
public Date getDateOfUpdated() {
return dateOfUpdated;
}
public void setDateOfUpdated(Date dateOfUpdated) {
this.dateOfUpdated = dateOfUpdated;
}
DataProjection
public interface DataProject {
String getDataAddress();
}
DataController
#GetMapping("/data/locations")
public List<DataProject> getDataAddress() {
return dataService.getDataAddress();
}
Postman Output
[
{
"dataAddress": null
},
{
"dataAddress": null
},
{
"dataAddress": null
},
{
"dataAddress": null
}
]
Spring won't return you only address using below query. It still return you DATA object
public interface DataRepository extends JpaRepository<Data, Long> {
#Query(value = "SELECT dataAddress FROM Data")
List<DataProject> getDataAddress();
}
for fetching only DataAddress you need to create a constructor inside Data model for DataAddress only
public Data(String dataAddress) {
this.dataAddress = dataAddress;
}
and your query will look like this:
public interface DataRepository extends JpaRepository<Data, Long> {
#Query(value = "SELECT new Data(dataAddress) FROM Data")
List<DataProject> getDataAddress();
}
Update 1 :
if you need this for other fields with same datatype and then above 'constructor' based method fails. There are some other alternatives:
You can fetch DATA object and use java stream map function to extract only 1 field. data.stream().map((data) -> data.getDataAddress()).collect(Collectors.toList())
You can use native SQL query to fetch only required fields.
#Query(value = "SELECT d.data_address FROM CCCData d", nativeQuery=true)
My Model Class is
#Data
public class Beer {
public Beer(int i, String string, float d) {
this.beerId = i;
this.beerName = string;
this.price = d;
}
public Beer() {
}
private int beerId;
private String beerName;
private float price;
}
And the Service Interface is
public interface IBeerService {
#Secured("ROLE_ADMIN")
#PreAuthorize("#beer.price > 0.0f")
Beer add(Beer beer);
#Secured("ROLE_USER")
#RolesAllowed("ROLE_USER")
List<Beer> getAll();
}
The interface is implemented as below.
#Service
public class BeerService implements IBeerService {
private List<Beer> beerRepository = new ArrayList<>();
#Override
public Beer add(Beer beerToAdd) {
if(!beerRepository.contains(beerToAdd)) {
beerToAdd.setBeerId(this.beerRepository.size()+1);
this.beerRepository.add(beerToAdd);
}
return beerToAdd;
}
#Override
public List<Beer> getAll() {
return beerRepository;
}
}
In the controller, I can able to see the object which is not null, in the debugger.
I am getting an error as
org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'price' cannot be found on null
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:213) ~[spring-expression-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:104) ~[spring-expression-5.1.9.RELEASE.jar:5.1.9.RELEASE]
God afternoon.
I am developing an app which show the places avalaible. In the case of Backend, researched about the SSE (Server-Sent-Event) and TailableCursors with MongoDB. I have done in Spring:
#Repository
public interface Repositorio extends ReactiveMongoRepository<Prueba, String> {
#Tailable
Flux<Prueba> findWithTailableCursorBy();
}
And the controller:
#RestController
#CrossOrigin
#RequestMapping
public class Controlador {
#Autowired
Repositorio repo;
#GetMapping(value = "/prueba", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Prueba> getTodos() {
return repo.findWithTailableCursorBy();
}
#GetMapping("/prueba2")
public Flux<Prueba> prueba() {
return repo.findAll();
}
#PostMapping("/prueba")
public Mono<Prueba> insert(#RequestBody Prueba prueba) {
return repo.save(prueba);
}
}
The items don't change when updated. I thought that with Tailable Cursors I would solve it. However, I see that no...
Is there any way to show the rafters in real time with Spring? So I'm using EventSource on the client-side.
PS: The class model (a capped collection) is:
#Document(collection = "pruebas")
// Lombok's annotations
#Data #NoArgsConstructor #AllArgsConstructor
#EqualsAndHashCode #ToString
public class Prueba {
#Id private String id;
private String nombre;
private boolean activo = false;
}