In the latter of html(Thymeleaf) below "<option th:each="platform : ${platforms}" Intelij Idea emphasizes red "platform.id" and "platform.name"
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/ad-edit.html]")]
Controller:
@GetMapping("/ads/{id}/edit") public String adEdit(@PathVariable(value = "id") int id, Model model) { List<Platform> platforms = platformRepository.findAll(); List<PlatformDTO> platformDTOList = platforms.stream().map(platform -> PlatformDTO.toDTO(platform)).collect(Collectors.toList()); Ad ad = adRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Ad having id " + id + " not found")); AdDTO adDto = new AdDTO(ad); model.addAttribute("platforms", platformDTOList); model.addAttribute("adDto", adDto); return "ad-edit"; } @PostMapping("/ads/{id}/edit") public String adUpdate(@PathVariable(value = "id") int id, @ModelAttribute("adDto") AdDTO adDto, Model model) { Ad ad = adRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Ad having id " + id + " not found")); ad.setPlatforms((platformRepository.findAllById(adDto.platformsIds))); ad.setName(adDto.name); ad.setAssetUrl(adDto.assetUrl); adRepository.save(ad); return "redirect:/ads"; } Entities and DTOs:
@Table(name = "ads") @EqualsAndHashCode(of = {"name"}) public class Ad { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String name; private Status status; private String assetUrl; @ManyToOne(optional = false, cascade = CascadeType.ALL) @JoinColumn(name = "campaign_id") private Campaign campaign; @ManyToMany @JoinTable(name = "ads_platforms", joinColumns = @JoinColumn(name = "ad_id"), inverseJoinColumns = @JoinColumn(name = "platform_id", nullable = true)) @Column(name = "platform") private List<Platform> platforms; public AdDTO(Ad ad) { this.id = ad.getId(); this.name = ad.getName(); this.assetUrl = ad.getAssetUrl(); this.status = ad.getStatus(); this.campaign = ad.getCampaign(); this.platformsIds = adPlatformIds(ad.getPlatforms()); } List<Integer> adPlatformIds(List<Platform> platforms){ List<Integer> platformIdsList = platforms.stream().map(platform -> platform.getId()).collect(Collectors.toList()); return platformIdsList; } } @Entity @Table(name = "platforms") @EqualsAndHashCode(of = {"name"}) @ToString(of = {"name"}) public class Platform { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", nullable = true) private Integer id; private String name; @ManyToMany @JoinTable(name = "ads_platforms", joinColumns = @JoinColumn(name = "platform_id", nullable = true), inverseJoinColumns = @JoinColumn(name = "ad_id")) @Column(name = "ad") private List<Ad> ads; public class PlatformDTO { public PlatformDTO() { } public Integer id; public String name; public List<Integer> adsIds; public static PlatformDTO toDTO(Platform platform) { if (platform == null) return null; PlatformDTO platformDTO = new PlatformDTO(); platformDTO.id = platform.getId(); platformDTO.name = platform.getName(); platformDTO.adsIds = platformAdsIds(platform.getAds()); return platformDTO; } static List<Integer> platformAdsIds(List<Ad> ads){ List<Integer> adIdsList = ads.stream().map(ad -> ad.getId()).collect(Collectors.toList()); return adIdsList; } ad-edit.html:
<!DOCTYPE html> <html> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x" crossorigin="anonymous"> <link rel="stylesheet" href="/css/style.css"/> <head> <meta charset="UTF-8"> <title>Редактирование обьявления</title> </head> <body> <header> <nav class="navbar navbar-light bg-light"> <form class="container justify-content-start"> <h3 class="caption">Редактирование обьявления <span th:text="${ad.name}"></span></h3> <button class="navbar-toggler" type="button"> <a href="../home.html" th:href="@{/home}">На главную</a></button> <button type="button" class="btn btn-light"> <a href="../info.html" th:href="@{/info}">Обе SQL Таблицы</a></button> <button type="button" class="btn btn-light"> <a href="../ads.html" th:href="@{/ads}">Обьявления</a></button> <button type="button" class="btn btn-light"> <a class="link" href="../campaigns.html" th:href="@{/campaigns}">Кампании</a></button> </form> </nav> </header> <form th:object="${adDto}" th:action="@{/ads/{id}/edit}" method="post"> <input type="text" th:value="${adDto.name}" th:field="*{adDto.name}" placeholder="Введите название обьявления" class="form-control"> <input type="text" th:value="${adDto.assetUrl}" th:field="*{adDto.assetUrl}" placeholder="Введите ссылку на рекламу" class="form-control"> <select class="form-control" th:field="*{adDto.platformsIds}" multiple="multiple" > <div><option th:each="platform : ${platforms}" th:value="${*platform.id*}" th:selected="${adDto.platformsIds.contains(*platform.id*)}" th:text="${*platform.name*}"> </option></div> </select> </div> <button type="submit" class="btn btn-success">Редактировать</button> </form> </body> </html>
${something.name}wheresomethingisnull. Use a debugger or extra logging to check if you are passingnullobjects to your model somewhere.