I have developed a service using Spring Boot. This is the code (simplified):
@RestController
@RequestMapping("/cars")
public class CarController {
@Autowired
private CarService carService;
@Autowired
private CarMapper carMapper;
@GetMapping("/{id}")
public CarDto findById(@PathVariable Long id) {
Car car = carService.findById(id);
return carMapper.mapToCarDto(car);
}
}
CarMapper
is defined using mapstruct. Here's the code (simplified as well):
@Mapper(componentModel="spring",
uses={ MakeModelMapper.class })
public interface CarMapper {
@Mappings({
//fields omitted
@Mapping(source="listaImagenCarro", target="rutasImagenes")
})
CarDto mapToCarDto(Car car);
String CAR_IMAGE_URL_FORMAT = "/cars/%d/images/%d"
/*
MapStruct will invoke this method to map my car image domain object into a String. Here's my issue.
*/
default String mapToUrl(CarImage carImage) {
if (carImage == null) return null;
return String.format(
CAR_IMAGE_URL_FORMAT,
carImage.getCar().getId(),
carImage.getId()
);
}
}
The JSON response I get when invoking the service:
{
"id": 9,
"make": { ... },
"model": { ... },
//more fields...
//the urls for the car images
"images": [
"/cars/9/images/1"
]
}
I need that the images
field returns valid URLs regarding the server and path where my app is deployed. For example, if I deploy the app using localhost through port 8080, I would like to get this:
{
"id": 9,
"make": { ... },
"model": { ... },
//more fields...
"imagenes": [
"http://localhost:8080/cars/9/images/1"
]
}
I've reviewed Building a Hypermedia-Driven RESTful Web Service, which seems what I want. Except that I only need it for these urls, I don't want to change my whole response object.
Is there another way to achieve it?
Spring HATEOAS provides a LinkBuilder service just for this purpose.
Try the following:
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
//...//
linkTo(methodOn(CarController.class).findById(9)).withRel("AddYourRelHere");
This should output an absolute URL that points to your resource. You are not following the HAL convention, so you should change or remove the part "withRel("")"
You can add this to the specific DTOs you want to change:
CarDto dto = carMapper.mapToCarDto(car);
if(dto.matches(criteria)){
dto.setUrl(linkTo...);
}
return dto;
By the way, all of this is shown in the section "Create a RestController" of the tutorial you mention.