i have object which has List and all this list has another List inside. problem is, i couldn't find the way nested looping with th:object attribute and i found solution from internet. currently i am having error when i am handling on controller but on thymeleaf UI there are no any errors.
successfully write to database that nested Object
error:
2023-11-23 13:39:55.795 ERROR 56621 --- [nio-8080-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.beans.InvalidPropertyException: Invalid property 'clients[0].children[0]' of bean class [com.JJEP.JJEP.application.ApplicationRequestDTO]: Illegal attempt to get property 'children' threw exception; nested exception is org.springframework.beans.NullValueInNestedPathException: Invalid property 'clients[0].children' of bean class [com.JJEP.JJEP.application.ApplicationRequestDTO]: Could not instantiate property type [com.JJEP.JJEP.application.client.child.ChildRequestDTO] to auto-grow nested property path; nested exception is java.lang.NoSuchMethodException: com.JJEP.JJEP.application.client.child.ChildRequestDTO.()] with root cause
java.lang.NoSuchMethodException: com.JJEP.JJEP.application.client.child.ChildRequestDTO.()
<!doctype html>
<html class="h-full" lang="en" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{_layout.html}" xmlns:th="http://www.w3.org/1999/xhtml">
<div layout:fragment="content">
<div th:if="${param.error}" class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 rounded-xl m-4" role="alert">
<p class="font-bold">Application error</p>
<p th:text="${error} ?: 'Something went wrong. Please try again later'"></p>
</div>
<!-- th:if="${#strings.equals(param.doubledClients, 'true')}"-->
<form method="post" th:action="@{/application-handler}" th:object="${formApplication}">
<div th:each="client: *{clients}">
<div class="flex flex-col md:flex-row p-4 justify-start">
<div class="flex flex-col flex-1 mb-8">
<h1 class="font-semibold">
Client
</h1>
<p class="text-gray-500">
Assets
</p>
</div>
<div class="grid grid-cols-2 gap-4 flex-1 lg:mr-32">
<div class="md:m-0">
<label for="familyName" class="block text-sm font-medium text-gray-900">Family name</label>
<div class="mt-2">
<input th:field="*{clients[__${clientStat.index}__].familyName}" type="text" name="familyName" id="familyName" autocomplete="name" class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full" min="0" max="3.4028235E38"
>
</div>
</div>
<div class="md:m-0">
<label for="property" class="block text-sm font-medium text-gray-900">Forename</label>
<div class="mt-2">
<input
th:field="*{clients[__${clientStat.index}__].forename}"
type="text"
name="forename"
id="forename"
autocomplete="name"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
min="0"
max="3.4028235E38"
>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('primaryProperty')}" th:errors="*{primaryProperty}"></span>
</div>
</div>
<div class="md:m-0">
<label for="property" class="block text-sm font-medium text-gray-900">Marital Status</label>
<div class="mt-2">
<input th:field="*{clients[__${clientStat.index}__].maritalStatus}" type="text" name="maritalStatus" id="maritalStatus" autocomplete="name" class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full" min="0" max="3.4028235E38"
>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('primaryProperty')}" th:errors="*{primaryProperty}"></span>
</div>
</div>
<div class="md:m-0">
<label for="property" class="block text-sm font-medium text-gray-900">Date Of Birth</label>
<div class="mt-2">
<input
th:field="*{clients[__${clientStat.index}__].dateOfBirth}"
type="date"
name="dateOfBirth"
id="dateOfBirth" autocomplete="name" class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
min="0"
max="3.4028235E38"
>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('primaryProperty')}" th:errors="*{primaryProperty}"></span>
</div>
</div>
<div class="md:m-0">
<label for="property" class="block text-sm font-medium text-gray-900">UK Domicile for IHT?</label>
<div class="mt-2">
<input
th:field="*{clients[__${clientStat.index}__].isUkIht}"
type="number"
name="isUkIht"
id="isUkIht"
autocomplete="name"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
min="0"
max="3.4028235E38"
>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('primaryProperty')}" th:errors="*{primaryProperty}"></span>
</div>
</div>
<div class="md:m-0">
<label for="property" class="block text-sm font-medium text-gray-900">Was the deceased's spouse's NRB used?</label>
<div class="mt-2">
<input
th:field="*{clients[__${clientStat.index}__].isSpouseNrb}"
type="number"
name="isSpouseNrb"
id="isSpouseNrb"
autocomplete="name"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
min="0"
max="3.4028235E38"
>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('primaryProperty')}" th:errors="*{primaryProperty}"></span>
</div>
</div>
<div class="md:m-0">
<label for="property" class="block text-sm font-medium text-gray-900">LPA in place?</label>
<div class="mt-2">
<input
th:field="*{clients[__${clientStat.index}__].isLpa}"
type="number"
name="isLpa"
id="isLpa"
autocomplete="name"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
min="0"
max="3.4028235E38"
>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('primaryProperty')}" th:errors="*{primaryProperty}"></span>
</div>
</div>
<div
class="md:m-0 col-span-full flex flex-row justify-between items-center space-x-4">
<!-- GAVNO CODE бля я не ебу как по другому -->
<a th:if="${clientStat.index == 1 and #strings.equals(param.doubledClients, 'true')}" th:href="@{/application(doubledClients=true, client1children=${client1children}, client2children=${client2children + 1})}" class="px-4 py-2 rounded-xl text-link hover:bg-link-back_hover">Add child</a>
<a th:if="${clientStat.index == 0 and #strings.equals(param.doubledClients, 'true')}" th:href="@{/application(doubledClients=true, client1children=${client1children + 1}, client2children=${client2children})}" class="px-4 py-2 rounded-xl text-link hover:bg-link-back_hover">Add child</a>
<a th:if="${clientStat.index == 0 and #strings.equals(param.doubledClients, 'false')}" th:href="@{/application(doubledClients=false, client1children=${client1children + 1}, client2children=${client2children})}" class="px-4 py-2 rounded-xl text-link hover:bg-link-back_hover">Add child</a>
<a th:if="!${param.doubledClients}" th:href="@{/application(doubledClients=false, client1children=${client1children + 1}, client2children=${client2children})}" class="px-4 py-2 rounded-xl text-link hover:bg-link-back_hover">Add child</a>
<a th:if="!${param.doubledClients}" th:href="@{/application(doubledClients=true, client1children=${client1children}, client2children=${client2children})}"
class="px-4 py-2 rounded-xl text-link hover:bg-link-back_hover">Add one more client</a>
<a th:if="${#strings.equals(param.doubledClients, 'false')}" th:href="@{/application(doubledClients=true, client1children=${client1children}, client2children=${client2children})}"
class="px-4 py-2 rounded-xl text-link hover:bg-link-back_hover">Add one more client</a>
<a th:if="${clientStat.index == 1 and #strings.equals(param.doubledClients, 'true')}" th:href="@{/application(doubledClients=false, client1children=${client1children}, client2children=${client2children - client2children})}"
class="px-4 py-2 rounded-xl text-link hover:bg-link-back_hover">Remove client</a>
</div>
<!-- submit or save -->
<div class="md:m-0 col-span-full flex flex-row justify-end border-t pt-4 space-x-4">
</div>
</div>
</div>
<div th:each="child : *{clients[__${clientStat.index}__].children}" class="flex flex-col md:flex-row p-4 justify-start">
<div class="flex flex-col flex-1 mb-8">
<h1 class="font-semibold">
Child
</h1>
<p class="text-gray-500">
</p>
</div>
<div class="grid grid-cols-2 gap-4 flex-1 lg:mr-32">
<div class="md:m-0">
<label for="property" class="block text-sm font-medium text-gray-900">Name</label>
<div class="mt-2">
<input
th:field="*{clients[__${clientStat.index}__].children[__${childStat.index}__].name}"
type="text"
name="childName"
id="childName"
autocomplete="name"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
min="0"
max="3.4028235E38"
>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('primaryProperty')}" th:errors="*{primaryProperty}"></span>
</div>
</div>
<div class="md:m-0">
<label for="property" class="block text-sm font-medium text-gray-900">Date of birth</label>
<div class="mt-2">
<input
th:field="*{clients[__${clientStat.index}__].children[__${childStat.index}__].dateOfBirth}"
type="date"
name="childDateOfBirth"
id="childDateOfBirth"
autocomplete="name"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
min="0"
max="3.4028235E38"
>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('primaryProperty')}" th:errors="*{primaryProperty}"></span>
</div>
</div>
<div class="md:m-0 col-span-full flex flex-row justify-between items-center space-x-4">
<a th:if="${clientStat.index == 0 and client1children >= 1 and #strings.equals(param.doubledClients, 'true')}" th:href="@{/application(doubledClients=true, client1children=${client1children - 1}, client2children=${client2children})}" class="px-4 py-2 rounded-xl text-link hover:bg-link-back_hover">Remove child</a>
<a th:if="${client1children >= 1 and #strings.equals(param.doubledClients, 'false')}" th:href="@{/application(doubledClients=false, client1children=${client1children - 1}, client2children=${client2children})}" class="px-4 py-2 rounded-xl text-link hover:bg-link-back_hover">Remove child</a>
<a th:if="${clientStat.index == 1 and client2children >= 1 and #strings.equals(param.doubledClients, 'true')}" th:href="@{/application(doubledClients=true, client1children=${client1children}, client2children=${client2children - 1})}" class="px-4 py-2 rounded-xl text-link hover:bg-link-back_hover">Remove child</a>
</div>
<!-- submit or save -->
<div class="md:m-0 col-span-full flex flex-row justify-end border-t pt-4 space-x-4">
</div>
</div>
</div>
</div>
<div>
<div class="flex flex-col flex-1 mb-8">
<h1 class="font-semibold">
Joint
</h1>
<p class="text-gray-500">
Assets
</p>
</div>
<div class="grid grid-cols-2 gap-4 flex-1 lg:mr-32">
<div class="md:m-0">
<label for="property" class="block text-sm font-medium text-gray-900">Primary Property</label>
<div class="mt-2">
<input
th:field="*{primaryProperty}"
type="number"
name="property"
id="property"
autocomplete="name"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
min="0"
max="3.4028235E38"
>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('primaryProperty')}" th:errors="*{primaryProperty}"></span>
</div>
</div>
<div class="md:m-0">
<label for="uk-property" class="block text-sm font-medium text-gray-900">UK Holiday Home</label>
<div class="mt-2">
<input
th:field="*{ukHolidayHome}"
type="number"
name="uk-property"
id="uk-property"
autocomplete="name"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
min="0"
max="3.4028235E38"
>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('ukHolidayHome')}" th:errors="*{ukHolidayHome}"></span>
</div>
</div>
<div class="md:m-0">
<label for="btl-property" class="block text-sm font-medium text-gray-900">BTL Property</label>
<div class="mt-2">
<input
th:field="*{btlProperty}"
type="number"
name="btl-property"
id="btl-property"
autocomplete="name"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
min="0"
max="3.4028235E38"
>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('btlProperty')}" th:errors="*{btlProperty}"></span>
</div>
</div>
<div class="md:m-0">
<label for="foreign-property" class="block text-sm font-medium text-gray-900">Foreign Property</label>
<div class="mt-2">
<input
th:field="*{foreignProperty}"
type="number"
name="foreign-property"
id="foreign-property"
autocomplete="name"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
min="0"
max="3.4028235E38"
>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('foreignProperty')}" th:errors="*{foreignProperty}"></span>
</div>
</div>
<div class="md:m-0 col-span-full">
<label for="foreign-will" class="block text-sm font-medium text-gray-900">Foreign Will</label>
<div class="mt-2">
<select
th:field="*{foreignWill}"
style="-webkit-appearance: none;"
id="foreign-will" name="select"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
>
<option value="Yes">Yes</option>
<option value="No">No</option>
</select>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('foreignWill')}" th:errors="*{foreignWill}"></span>
</div>
</div>
<div class="md:m-0">
<label for="investment" class="block text-sm font-medium text-gray-900">Investment</label>
<div class="mt-2">
<input
th:field="*{investment}"
type="number"
name="investment"
id="investment"
autocomplete="name"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
min="0"
max="3.4028235E38"
>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('investment')}" th:errors="*{investment}"></span>
</div>
</div>
<div class="md:m-0">
<label for="savings-cash" class="block text-sm font-medium text-gray-900">Savings & Cash</label>
<div class="mt-2">
<input
th:field="*{savingsCash}"
type="number"
name="savings-cash"
id="savings-cash"
autocomplete="name"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
min="0"
max="3.4028235E38"
>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('savingsCash')}" th:errors="*{savingsCash}"></span>
</div>
</div>
<div class="md:m-0">
<label for="personal-live-cover" class="block text-sm font-medium text-gray-900">Personal Life Cover</label>
<div class="mt-2">
<input
th:field="*{personalLifeCover}"
type="number"
name="personal-live-cover"
id="personal-live-cover"
autocomplete="name"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
min="0"
max="3.4028235E38"
>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('personalLifeCover')}" th:errors="*{personalLifeCover}"></span>
</div>
</div>
<div class="md:m-0">
<label for="trust" class="block text-sm font-medium text-gray-900">Already in trust?</label>
<div class="mt-2">
<div class="mt-2">
<select
th:field="*{trust}"
style="-webkit-appearance: none;"
id="trust"
name="select"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
>
<option value="Yes">Yes</option>
<option value="No">No</option>
</select>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('trust')}" th:errors="*{trust}"></span>
</div>
</div>
</div>
<div class="md:m-0 col-span-full">
<label for="blood-protection" class="block text-sm font-medium text-gray-900">Blood Protection</label>
<div class="mt-2">
<select
th:field="*{isBloodProtection}"
style="-webkit-appearance: none;"
id="blood-protection" name="select"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
>
<option value="Yes">Yes</option>
<option value="No">No</option>
</select>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('isBloodProtection')}" th:errors="*{isBloodProtection}"></span>
</div>
</div>
<div class="md:m-0 col-span-full">
<label for="generation-iht" class="block text-sm font-medium text-gray-900">Generation IHT</label>
<div class="mt-2">
<select
th:field="*{isGenerationIht}"
style="-webkit-appearance: none;"
id="generation-iht" name="select"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full"
>
<option value="Yes">Yes</option>
<option value="No">No</option>
</select>
<span class="text-xs text-red-500" th:if="${#fields.hasErrors('isGenerationIht')}" th:errors="*{isGenerationIht}"></span>
</div>
</div>
<div class="md:m-0 col-span-full">
<label for="notes" class="block text-sm font-medium text-gray-900">Notes (Optional)</label>
<div class="mt-2">
<textarea
th:field="*{notes}"
id="notes"
name="about"
rows="3"
class="border border-gray-300 px-4 py-2 rounded-xl focus:outline-primary block w-full">
</textarea>
</div>
</div>
</div>
</div>
<div>
<div>
<!-- submit or save -->
<div class="md:m-0 col-span-full flex flex-row justify-end border-t pt-4 space-x-4">
<button type="button" class="px-4 py-2 text-primary hover:bg-gray-100 rounded-xl">
Cancel
</button>
<button type="submit" class="px-4 py-2 bg-primary text-white hover:bg-primary-hover rounded-xl">
Submit
</button>
</div>
</div>
</div>
</form>
</div>
</body>
</html>