I have next situation, i have controller interface:
package com.example.poster_final_project.controllers.api;
import com.example.poster_final_project.service.dto.api.IPage;
import org.springframework.web.bind.annotation.*;
@RequestMapping("/poster/event")
public interface IController<C,R,P extends IPage<?>> {
@PostMapping(value = "/{type}")
C create(@RequestBody C eventDto, @PathVariable String type);
@GetMapping(value = "/{type}/{uuid}")
R readEventInfo(@PathVariable String type,@PathVariable String uuid);
@GetMapping(value = "/{type}")
P readPageOfEvent(@PathVariable String type,
@RequestParam(required = false) Integer size,
@RequestParam(required = false) Integer page);
@PutMapping(value = "/{type}/{uuid}/dt_update/{dt_update}")
C updateEvent(@PathVariable String type,
@PathVariable String uuid,
@PathVariable(name = "dt_update") String dtUpdate,
@RequestBody C eventBody);
}
which is extended by another 2 controller, but already with concrete types:
first
package com.example.poster_final_project.controllers.api;
import com.example.poster_final_project.service.dto.concerts.EventConcertToCreate;
import com.example.poster_final_project.service.dto.concerts.EventConcertToRead;
import com.example.poster_final_project.service.dto.concerts.PageOfConcertToRead;
public interface IEventConcertController extends IController<EventConcertToCreate, EventConcertToRead, PageOfConcertToRead> {}
second
package com.example.poster_final_project.controllers.api;
import com.example.poster_final_project.service.dto.films.EventFilmToCreate;
import com.example.poster_final_project.service.dto.films.EventFilmsToRead;
import com.example.poster_final_project.service.dto.films.PageEventFilmsToShow;
public interface IEventFilmsController extends IController<EventFilmToCreate, EventFilmsToRead, PageEventFilmsToShow>{}
But i have a problem, i can't change URLs, to exclude Ambiguous mapping. I thought about one input controller that will redirect already to specific, but it's differrnt types in @RequestBody. So what can i do (other than renaiming URLs), to exclude Ambiguous mapping?
CodePudding user response:
I think I would use a fixed path per type, and abstract over the service layer.
interface EventService<E extends Event> {
E create(E data);
E get(String uuid);
E update(E data);
}
interface DtoMapper<E extends Event, D extends Dto<E>> {
E toDomainObject(D data);
D toDto(E domainObject);
}
@RequestMapping("/poster/event")
class EventController {
EventService<Film> filmService;
EventService<Concert> concertService;
DtoMapper<Film> filmMapper;
DtoMapper<Concert> concertMapper;
@PostMapping(value = "/concert")
Concert create(@RequestBody ConcertDto eventDto) {
return concertService.create(concertMapper.toDomainObject(eventDto));
}
@PostMapping(value = "/film")
Film create(@RequestBody FilmDto eventDto) {
return filmService.create(filmMapper.toDomainObject(eventDto));
}
@GetMapping(value = "/concert/{uuid}")
Concert getConcert(@PathVariable String uuid) {
return concertMapper.toDto(concertService.get(uuid));
}
@GetMapping(value = "/film/{uuid}")
Film getFilm(@PathVariable String uuid) {
return filmMapper.toDto(filmService.get(uuid));
}
...
}
That makes the controller responsible for the translation between incoming data and service layer, and you have a clean service with the same functionality for each type.
There are a lot of methods in the controller, but I don't think you'll have a hard time having a type determined by a String along with a type Dto object in the method signature. You can return Object and the objectmapper will create valid JSON outbound, and incoming you can declare a Map<String, String>
as a body that can construct the object you need, but I would bet you'll have worse code down the road if you do that.