• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

[Spring MVC] Model zwraca null

VPS Starter Arubacloud
+1 głos
549 wizyt
pytanie zadane 9 sierpnia 2018 w Java przez Przemyslaw Użytkownik (610 p.)

Cześć! Potrzebuję zrobić tak, aby za pomocą jednego formularza, uzupełnić 3 tabele(Account, Customer, Users) które są od siebie wzajemnie zależne.

W tym celu, utworzyłem klasę RegisterObject, która agreguje pod sobą wszystkie 3 encje:

package main.com.java.entity;

public class RegisterObject {

    private Account account;
    private Customer customer;
    private Users users;

    public RegisterObject(Account account, Customer customer, Users users) {
        this.account = account;
        this.customer = customer;
        this.users = users;
    }

    public Account getAccount() {
        return account;
    }

    public void setAccount(Account account) {
        this.account = account;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public Users getUsers() {
        return users;
    }

    public void setUsers(Users users) {
        this.users = users;
    }
}

 

Jednak po uzupełnieniu formularza w widoku, wartości te nie są przeniesione na model, przez co zwraca mi nullowe wartości na parametrach obiektów Account, Users, Customer. 

Metody w kontrolerze:

@GetMapping("/showFormForAddAccount")
	public String showFormForAddAccount(Model theModel){
        RegisterObject registerObject = new RegisterObject(new Account(), new Customer(), new Users());
		theModel.addAttribute("registerObject", registerObject);
		
		return "account-form";
	}
	
	@PostMapping("/saveAccount")
	public String saveAccount(@ModelAttribute("registerObject") RegisterObject registerObject) {
		registerObject.getAccount().setAccountNumber(accountNumberGenerator.generateAccountNumber());
		registerObject.getUsers().setPassword(passwordGenerator.generatePassword());
		registerObject.getCustomer().setIdOfAccount(registerObject.getAccount().getAccountID());
		registerObject.getUsers().setUsername(registerObject.getAccount().getUsername());
        accountService.addAccount(registerObject.getAccount());
		usersService.addUser(registerObject.getUsers());
		customerService.addCustomer(registerObject.getCustomer());

		return "redirect:/customer/list";
	}

 

Formularz:

<div class="table-container">

		<form:form action="saveAccount" modelAttribute="registerObject" method="POST">

			<!-- need to associate this data with customer id -->
			<form:hidden path="account.accountID" />

			<table>
				<tbody>

				<tr>
					<td><label>Balance:</label></td>
					<td><form:input path="account.balance" /></td>
				</tr>

				<tr>
					<td><label>Username:</label></td>
					<td><form:input path="account.username" /></td>
				</tr>

				<tr>
					<td><label>First name:</label></td>
					<td><form:input path="customer.firstName" /></td>
				</tr>

				<tr>
					<td><label>Last name:</label></td>
					<td><form:input path="customer.lastName" /></td>
				</tr>

				<tr>
					<td><label>Country:</label></td>
					<td><form:input path="customer.country" /></td>
				</tr>

				<tr>
					<td><label>User Enable:</label></td>
					<td><form:input path="users.enabled" /></td>
				</tr>

				<tr>
					<td><label></label></td>
					<td><input type="submit" value="Save" class="save" /></td>
				</tr>


				</tbody>
			</table>

 

Czy ktoś zna rozwiązanie tego problemu?

Dodam, że jeżeli ktoś zna lepszy sposób na uzupełnienie w jednym czasie 3 tabeli, to chętnie go poznam. :)

3 odpowiedzi

+1 głos
odpowiedź 10 sierpnia 2018 przez mbabane Szeryf (79,280 p.)
wybrane 13 sierpnia 2018 przez Przemyslaw
 
Najlepsza
Spróbowałem odtworzyć Twój przypadek u siebie i jedyne do czego się przywalił Spring to, to że w RegisterObject nie było domyślnego konstruktora. Po jego dodaniu zaczęło działać i w metodzie mapującej POST nie było nula.

 

Jeśli chodzi o inną metodę to zamiast JSP można użyć Thymeleaf.
komentarz 12 sierpnia 2018 przez Przemyslaw Użytkownik (610 p.)
Hmmm, naprawdę nic nie zmieniałeś? U mnie mimo wszystko nie działa.

Nadal mam nie rozwiązany problem.

Póki co, próbuję poznać JSP. :)
komentarz 12 sierpnia 2018 przez mbabane Szeryf (79,280 p.)
Jeśli możesz to wgraj projekt na githuba  to popatrzę, bo może jest jakiś szczegół, którego nie uwzględniłem.
komentarz 12 sierpnia 2018 przez mbabane Szeryf (79,280 p.)
edycja 12 sierpnia 2018 przez mbabane

To jest chyba ten kontroler, ktorego fragmetn jest w temacie:

https://github.com/PrzemyslawZnojek/BankApplication/blob/changingArchitecture/src/main/com/java/controller/AccountController.java

Nic dziwnego ze dostaje Nulla bo pole registerObject nie jest nigdzie inicjowane, zrób np. tak jak masz w temacie:

RegisterObject registerObject = new RegisterObject(new Account(), new Customer(), new Users());
theModel.addAttribute("registerObject", registerObject);

 

Usuń stąd @Autowired, dlatego, że dane do tych obiektów mają być podawane przez użytkownika, nie przez aplikację:

https://github.com/PrzemyslawZnojek/BankApplication/blob/changingArchitecture/src/main/com/java/entity/RegisterObject.java

Zainicjuj tylko gdzieś te obiekty (account, customer i users), najlepiej jest to robić zdaje się poprzez konstruktor tak jak tu:

RegisterObject registerObject = new RegisterObject(new Account(), new Customer(), new Users());

Do tego do klasy RegisterObject dodaj pusty konstruktor, ponieważ zdaje się, że to:

public String saveAccount(@ModelAttribute("registerObject") RegisterObject registerObject)

Najpierw inicjuje obiekt poprzez własnie pusty konstruktor, a dopiero potem za pomocą setterów wstawia odpowiednie wartości.

Na razie tyle zauważyłem.

komentarz 12 sierpnia 2018 przez Przemyslaw Użytkownik (610 p.)

Hmmm, proprawiłem to i nadal za pomocą debug'a widzę, że wartości z formularza nie są uzupełnione:

komentarz 12 sierpnia 2018 przez mbabane Szeryf (79,280 p.)

Po kliknięciu submit są nulami i NullPointera rzuca czy cos?

komentarz 12 sierpnia 2018 przez Przemyslaw Użytkownik (610 p.)
Dokładnie tak.
1
komentarz 13 sierpnia 2018 przez mbabane Szeryf (79,280 p.)
edycja 13 sierpnia 2018 przez mbabane
Nie ma setterów/getterow w encji Customer i Account.

Z tymi setterami i getterami to jest czasem wkurzające, raz chyba 30 min straciłem bo REST API mi nie chciało JSONa zwrócić i okazało się że nie mam setterów i getterów...
komentarz 13 sierpnia 2018 przez Wiciorny Ekspert (269,120 p.)
albo czasem brak Domyślnego :D Construktora przy pamowaniu, lub dla testów też powodował wysypy.

Pamięam - jeszcze jak bez sonar linta pracowałem który fajnie to przypominał,
komentarz 13 sierpnia 2018 przez Przemyslaw Użytkownik (610 p.)

@mbabane, Ehhhh. Dodanie Setterów i Getterów pomogło. Rozumiem, że Spring wykorzystuje te metody i mimo że IntelliJ pokazuje mi je jako nieużywane, to framework je stosuje? 

 

komentarz 13 sierpnia 2018 przez Przemyslaw Użytkownik (610 p.)

@mbabane,  Jestem bardzo wdzięczny za pomoc, ale wykorzystam jeszcze moment atencji.

Po pierwsze, prosiłbym jeszcze o udzielenie odpowiedzi na powyższe pytanie.

Po drugie, czy masz do polecenia jakąś lekturę na temat springa. Teraz widzę, że sam tutorial to za mało.

Po trzecie, czy wiesz może, czemu rzuca mi ten błąd w constraint'ach:

13-Aug-2018 22:57:19.660 WARN [http-nio-8080-exec-2] org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logExceptions SQL Error: 1452, SQLState: 23000
13-Aug-2018 22:57:19.660 ERROR [http-nio-8080-exec-2] org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logExceptions Cannot add or update a child row: a foreign key constraint fails (`bank_application`.`customer`, CONSTRAINT `Customer_ibfk_1` FOREIGN KEY (`idOfAccount`) REFERENCES `account` (`accountID`))
org.hibernate.exception.ConstraintViolationException: could not execute statement
	at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)
	at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
	at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
	at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97)
	at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:178)
	at org.hibernate.dialect.identity.GetGeneratedKeysDelegate.executeAndExtract(GetGeneratedKeysDelegate.java:57)
	at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:42)
	at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2919)
	at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3510)
	at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:81)
	at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:637)
	at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:282)
	at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:263)
	at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:317)
	at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:318)
	at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:275)
	at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:182)
	at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:113)
	at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
	at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
	at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:97)
	at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
	at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:660)
	at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:652)
	at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:647)
	at main.com.java.dao.implementation.CustomerDAOImpl.addCustomer(CustomerDAOImpl.java:56)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:338)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:206)
	at com.sun.proxy.$Proxy49.addCustomer(Unknown Source)
	at main.com.java.service.domain.implementation.CustomerServiceImpl.addCustomer(CustomerServiceImpl.java:34)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:338)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:197)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
	at com.sun.proxy.$Proxy50.addCustomer(Unknown Source)
	at main.com.java.controller.AccountController.saveAccount(AccountController.java:59)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:871)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:777)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:881)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:855)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:124)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:494)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:651)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:407)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:754)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1376)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`bank_application`.`customer`, CONSTRAINT `Customer_ibfk_1` FOREIGN KEY (`idOfAccount`) REFERENCES `account` (`accountID`))
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
	at com.mysql.jdbc.Util.getInstance(Util.java:408)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:936)
	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3976)
	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3912)
	at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2530)
	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2683)
	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2486)
	at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1858)
	at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2079)
	at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2013)
	at com.mysql.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:5104)
	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1998)
	at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:384)
	at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175)
	... 116 more

Domyślam się, że może być coś złego w mapowaniu, jednak nie mogę tego namierzyć.

1
komentarz 14 sierpnia 2018 przez mbabane Szeryf (79,280 p.)
edycja 14 sierpnia 2018 przez mbabane

Na to wychodzi, aż tak głęboko nie znam Springa żeby to sensownie wytłumaczyć, pod spodem prawdopodobnie siedzi mechanizm refleksji, dlatego, że program nie jest myślącym bytem i nie jest wstanie przewidzieć co będzie miała dana klasa. Być może pobiera listę metod i odseparowuje te, które zaczynają się na get/set, bo za pomocą refleksji można wywoływać metody (nawet prywatne):

public class SomeClass {
    private String name;
    private String lastName;

    public SomeClass() {
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLastName() {
        return this.lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public void method() {
    }

    public String toString() {
        return "SomeClass{name='" + this.name + '\'' + ", lastName='" + this.lastName + '\'' + '}';
    }
}
public class Main
{
    public static void main(String[] args) throws Exception
    {
        SomeClass someClass = new SomeClass();
        Method[] allMethods = someClass.getClass().getMethods();

        List<Method> onlySetters = new ArrayList<>();

        for (Method method : allMethods)
        {
            if (method.getName().startsWith("set"))
                onlySetters.add(method);
        }

        onlySetters.forEach( m -> System.out.println( m.getName() ) );

        Method setter = onlySetters.get(0);
        setter.invoke(someClass, "arg");
        System.out.println(someClass);
    }
}

Ale jak to dokładnie jest to póki co jeszcze nie wiem. Mogę się tylko, na podstawie tego co wiem do tej pory, domyślać (gdybym miał zaimplementować podobny mechanizm pewnie bym jakoś kombinował z tymi refleksjami).

W Javie 10 ma zdaje się byc takie coś jak datum, które będzie domyślnie posiadało settey i gettery (w dużym uproszczeniu). Punkt 3:

https://javastart.pl/b/java/co-nowego-w-javie/

 

A ten błąd z constraintami, to co robisz, że Ci powstaje?

komentarz 14 sierpnia 2018 przez Przemyslaw Użytkownik (610 p.)
Hmmm, bardzo ciekawe. Już rozumiem ten punkt widzenia.

Błąd, to efekt wykonania submit'a, w formularzu. Poprawnie tworzy się obiekt na bazie typu User, typu Account, ale wyrzuca błąd przy próbie utworzenia Customer'a.
1
komentarz 14 sierpnia 2018 przez mbabane Szeryf (79,280 p.)
edycja 14 sierpnia 2018 przez mbabane
Nie jestem pewny ale zdaje się, że przez to, że na wszystkich polach masz zastosowane CascadeType.ALL - oznacza to tyle że jeśli zapisujesz do bazy Account, który ma przypisaną referencję do Customer to Customer jest automatycznie zapisywany do bazy -> kaskadowo (i pole User też). I teraz gdy próbujesz ręcznie zapisać Customera to po pierwsze on już jest zapisany, a po drugie jak ustawiasz mu referencje do Account to hibernate próbuje zapisać w bazie ponownie obiekt Account ale, że już on istnieje w tabeli to wywala błąd, że zostały naruszone jakieś tam constrainty. (Usun testowo CascadeType.ALL z wszystkich klas i zobacz co się stanie).

Edit, ale masz tam użyte insertable false, co, o ile dobrze to rozumiem, zapobiega tworzeniu obiektu z racji danej encji.
1
komentarz 14 sierpnia 2018 przez Wiciorny Ekspert (269,120 p.)

Wiecie co : co do faktu tego

Dlaczego SPRING potrzebuje tutaj gettera/settera ? 

czytając rzetelnie dokumentacje i ksiazki : generalnie biorąc pod uwagę to że SPRING powstał na bazie POJO [ które zawsze w swojej implementacji wymagały gettera i settera ] to jest wydje mi się odpowiedź dlaczego jest mu to tutaj potrzebne

W sytuacji kiedy  tworzymy obiekty z domyślnym tzw konstruktorem, a nie np z parametrami, gdzie podajemy parametry i ustawiamy w konstruktorze  

https://stackoverflow.com/questions/7455630/is-it-necessary-to-have-getters-and-setters-in-pojos 

 

A i jeszcze co do CASCADE.ALL -> To @mbabane ma racje  zastosowanie tego w perzystencji HIBERNATE powoduje że wszystkie operacje 

(PERSIST, REMOVE, REFRESH, MERGE, DETACH) 

są kaskadowe, więc zarówno usuwanie obiektu User -> usunie obiekt wewnętrzny który np jest dowiązaniem Account i analogicznie przy tworzeniu będzie wymagał tego tak na logike moją https://stackoverflow.com/questions/13027214/jpa-manytoone-with-cascadetype-all

 

komentarz 14 sierpnia 2018 przez Przemyslaw Użytkownik (610 p.)

@mbabane, już sobie poradziłem.

Zwracało mi błąd, gdyż nie miałem uzupełnianego Foreing Key.

Początkowo:

public String saveAccount(@ModelAttribute("registerObject") RegisterObject registerObject) {
		registerObject.getAccount().setAccountNumber(accountNumberGenerator.generateAccountNumber());
		registerObject.getUsers().setPassword(passwordGenerator.generatePassword());
		registerObject.getUsers().setUsername(registerObject.getAccount().getUsername());
		registerObject.getCustomer().setIdOfAccount(registerObject.getAccount().getAccountID());		
                registerObject.getUsers().setEnabled(true);
		accountService.addAccount(registerObject.getAccount());
		usersService.addUser(registerObject.getUsers());
		customerService.addCustomer(registerObject.getCustomer());

		return "redirect:/customer/list";
	}

Obecnie:

public String saveAccount(@ModelAttribute("registerObject") RegisterObject registerObject) {
		registerObject.getAccount().setAccountNumber(accountNumberGenerator.generateAccountNumber());
		registerObject.getUsers().setPassword(passwordGenerator.generatePassword());
		registerObject.getUsers().setUsername(registerObject.getAccount().getUsername());
		registerObject.getUsers().setEnabled(true);
		accountService.addAccount(registerObject.getAccount());
		usersService.addUser(registerObject.getUsers());
		registerObject.getCustomer().setIdOfAccount(registerObject.getAccount().getAccountID());
		customerService.addCustomer(registerObject.getCustomer());
		
		return "redirect:/customer/list";
	}

 

Przeniosłem po prostu moment spisywania ID Accounta na pole Customer'a. 

Wcześniej po prostu nie miało co spisać, bo sam ID tworzy się w momencie dodania obiektu na bazę.

 

Mam kolejne pytanie, być może przesadzam z nimi, ale bardzo dużo się dzięki wam uczę.

Chciałbym dodać do mojej aplikacji testy jednostkowe. Jestem w tym temacie póki co zielony. Czytałem kiedyś że nie warto pisać testy na warstwie perzystencji, bo jedyne co sprawdzimy, to to, czy działa framework(w tym wypadku hibernate). Obecnie w warstwie serwisów mam jedynie generatory i serwisy domenowe(te pomiędzy kontrolerami a DAO). Czy ja obecnie nie mam co testować? Czy da się w jakiś sposób testować generatory?

1
komentarz 16 sierpnia 2018 przez Wiciorny Ekspert (269,120 p.)
Testujesz swoje metody i ich działanie według SOLID -> GŁÓWNIE S - > Single Responsibility principe -  czyli 1 metoda - 1 funkcjonalność

Wszystkie metody powinny byc testowane, bo to ty je pisałeś i trzeba sprawdzić przypadki ich działania czy faktycznie one są poprawnie implementowane.

Sprawdź sobie fejkowe obiekty " MOCKITO biblioteka " Mocito junit

https://www.tutorialspoint.com/mockito/mockito_junit_integration.htm
+1 głos
odpowiedź 10 sierpnia 2018 przez Wiciorny Ekspert (269,120 p.)
edycja 10 sierpnia 2018 przez Wiciorny
 RegisterObject registerObject = new RegisterObject(new Account(), new Customer(), new Users());

w każdym Mapowaniu tworzysz nowy obiekt? Pusty... ?

więc nawet wywołując wcześniej 

 @PostMapping("/saveAccount")

to i tak otrzymasz nową czystą instancje registerObject...

zależy jak wyglądają konstruktory dla posłanych obiektów,  :) 

(new Account(), new Customer(), new Users()

Co zawierają?

CO NAJWAŻNIEJSZE: JEŚLI TO JEST SPRING MVC...

to powinieneś: po pierwsze stosować DEPENDENCY INJECTION ... automatycznie wstrzykiwać i wiązać obiekty.... 

i kontrole obiektów zostawić Springowi i IoC kontenerowi ... , czemu twoja klasa w takim razie nie jest Componentem?  

Jedno pytanie też mi się nasuwa: czemu GET-> z racji pobierania zasobu u Ciebie dodaje atrybut ? Który generalnie tworzy pusty? :D ... 

A post okej, nie tworzy obiektu ale przypisuje do otrzymanego wartości... więc to co u Ciebie dzieje się w metodzie get-> jest robione dla lokalnego elementu 

1
komentarz 10 sierpnia 2018 przez mbabane Szeryf (79,280 p.)

Jedno pytanie też mi się nasuwa: czemu GET-> z racji pobierania zasobu u Ciebie dodaje atrybut ? Który generalnie tworzy pusty?

Nie wiem czy to masz na myśli ale wydaje mi się, że autor nie robi REST API tylko zwykła aplikacje internetową, co zdaje się zmienia trochę postać rzeczy. To GET będzie wywoływane, w momencie wejścia na stronę z formularzem, który ma odwoływać się własnie do tego atrybutu ustawianego w metodzie z GetMapping. Po kliknięciu submit w formularzu przechodzi POSTEM do saveAccount gdzie atrybut przyjmowany jako parametr metody odpowiada referencji z metody GET, dzięki temu jest dostęp do danych z obiektu z formularza.

komentarz 10 sierpnia 2018 przez Wiciorny Ekspert (269,120 p.)
no tak masz racje, tylko że napisane w temacie jest SPRING-MVC, a to z kolei do czegoś zoobowiązuje, że jak stosujemy FRAMEWORK i jakiś "feature" z niego to powinien być on implementowany w całości a nie tu trochę tego, trochę tego- dla mnie kod jest niezrozumiały troszeczkę :D w stosunku do tematu autora.

 

Dzięki za reszte wypowiedzi co do parametryzacji tutaj metody
GET-> PUT
komentarz 10 sierpnia 2018 przez mbabane Szeryf (79,280 p.)
O ile się nie mylę to SPRING-MVC nie zobowiązuje do pisania REST API (jeśli to masz na myśli). Można go zdaje się wykorzystać jako zamiennik JSF w Javie EE.
komentarz 12 sierpnia 2018 przez Przemyslaw Użytkownik (610 p.)

@Wiciorny, Zgadza się, popełniłem błąd, że nie tworzę tego za pomocą IoC.

Czy klasę RegisterObject, powinienem utworzyć w tym samym module co inne encje? Jakie powinno być oznaczenie tej klasy? @Component? Niestety jak próbuję wykorzystać @Entity, zgłasza mi brak primary key.

Jak powinienem powiązać obiekty Account, Customer i Users z RegistejObject? Gdy wykorzystuję @Autowired, IDE zgłąsza mi, że te obiekty nie są "beansami" Czy to oznacza, że Klasy typu @Entity, nie są beansami?

komentarz 12 sierpnia 2018 przez mbabane Szeryf (79,280 p.)

 Klasy typu @Entity, nie są beansami

Tak.

@Component zdaje się że stosuje się kiedy klasa zawiera jakąś logikę aplikacji. W przypadku RegisterObject tak raczej nie jest, więc zrobienie z niej Componentu nie będzie zbyt dobrym posunięciem.

@Entity oznacza się klasy, które mają być mapowane (przekształcone) na tabele bazy danych. Jeśli chodzi o RegisterObject to chyba to nie jest Twoim celem, więc oznaczenie jako @Entity też nie będzie potrzebne.

komentarz 12 sierpnia 2018 przez Przemyslaw Użytkownik (610 p.)
Hmm, więc jakie tutaj powinno być oznaczenie, abym mógł skorzystać z kontenera IoC?
komentarz 12 sierpnia 2018 przez mbabane Szeryf (79,280 p.)
Wydaje mi się, że do obiektu RegisterObject będzie to mało użyteczne.
komentarz 12 sierpnia 2018 przez Przemyslaw Użytkownik (610 p.)
Czyli dobrze, że nie skorzystałem wtedy z kontenera IoC? Czyli używając springa, nie trzeba zawsze polegać na DI i IoC?
komentarz 14 sierpnia 2018 przez Wiciorny Ekspert (269,120 p.)
Spring zawsze używa  IoC i DI bo taka jest jego specyfikacja... jeśli dany kontener/szablon/klase/ etc.  uzależnisz od Springa to niestety ApplicationContext bedzie tak realizowany
0 głosów
odpowiedź 10 sierpnia 2018 przez Aisekai Nałogowiec (42,190 p.)
A nie możesz po prostu @RequestBody i przeslac to za pomocą put albo post?
komentarz 12 sierpnia 2018 przez Aisekai Nałogowiec (42,190 p.)
@Wiciorny slyszalem, że jesli chce się coś utworzyć - to należy skorzystac z post. Jeżeli chce się podmienić (caly obiekt, np zalogowanego Usera) to należy skorzystac z put. Natomiast jeżeli chce się zmienic istniejący obiekt, to wtedy powinno sie uzywac Patch.
komentarz 12 sierpnia 2018 przez Wiciorny Ekspert (269,120 p.)
tzn PUT służąc do aktualizacji w REST api tak czy siak działa na bazie "podmienienia całego zasobu, czyli cała encja jest zastąpiona nową "  - taka jest metodyka działania PUT, z Patch się nie spotkałem.
komentarz 12 sierpnia 2018 przez Przemyslaw Użytkownik (610 p.)

@Wiciorny, Czytam książki, które dotyczą ogólnie programowania, takie jak Clean Code etc. Samego frameworka, uczę się z tutorialu. Jeżeli masz do polecenia jakąś lekturę, chętnie ją poznam.

1
komentarz 12 sierpnia 2018 przez mbabane Szeryf (79,280 p.)

PATCH chyba rzadko kiedy jest wykorzystywany w REST API. Np. na githubie przy PATCH jest coś takiego:

Used for updating resources with partial JSON data. For instance, an Issue resource has title and body attributes. A PATCH request may accept one or more of the attributes to update the resource. PATCH is a relatively new and uncommon HTTP verb, so resource endpoints also accept POST requests.

( https://developer.github.com/v3/#http-verbs )

Z tego też co zrozumiałem z książek PUT-em za każdym razem trzeba podawać cały obiekt, natomiast PATCHEM można podać jego część.

Przykładowo  np. API Facebooka do edycji używa POST. PATCHA chyba nie używają,  API YouTuba też nie wspiera PATCH - mają standardowe GET, PUT, POST, DELETE.

komentarz 13 sierpnia 2018 przez Wiciorny Ekspert (269,120 p.)
no tak PUTEM musimy podawać cały obiekt: dlatego że to wynika z idempotentne -> czyli z algebry zbiór jakby jest podmieniany, Paradoksalnie jak tranzakcje :D albo w całości albo wcale [ tutaj całością jest obiekt] .

W sumie z punktu widzenia - oszczędności, czy tez pamięci to bardzo nieoptymalne. Ciekaw jestem ( bo to pewnie od implementacji zależy ) czy obiekt bedzie nadpisany co jest mniej pamięcio rzerne, czy np HIBERNATE   na takich obiektach u siebie skorzysta z tego co zawsze czyli WYPIERNICZY, USUNIE ;D i doda nowy obiekt, a nie go nadpisze...

Podobne pytania

0 głosów
1 odpowiedź 496 wizyt
pytanie zadane 14 października 2021 w Java przez Tajniakkk Użytkownik (600 p.)
+1 głos
1 odpowiedź 416 wizyt
pytanie zadane 14 sierpnia 2021 w Java przez DziQu Początkujący (420 p.)
0 głosów
1 odpowiedź 304 wizyt
pytanie zadane 25 listopada 2019 w Java przez Piotrek1604 Użytkownik (560 p.)

92,451 zapytań

141,261 odpowiedzi

319,073 komentarzy

61,853 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...