Home > Software design >  Unsure of why java/spring app is not saving my entity properly to MySQL database (when it is correct
Unsure of why java/spring app is not saving my entity properly to MySQL database (when it is correct

Time:01-16

I've gone through most or all the StackOverflow questions relating to this question, and I haven't seen an answer that solves my problem. I have this basic app that saves two different types of entities to a database (User and Quote). I am able to save the User entity just fine, but the Quote entity is not getting saved.

App Controller

@Controller
public class AppController {

    @Autowired
    private UserRepository userRepository;

    @Autowired 
    private QuoteRepository quoteRepository;

    @GetMapping("/")
    public String viewHomePage() {
        return "index";
    }

    @GetMapping("/register")
    public String viewRegistrationForm(Model model) {
        User newUser = new User();
        model.addAttribute("user", newUser);
        return "signup_form";
    }

    @PostMapping("/processRegister")
    public String processRegister(User user) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encodedPassword = passwordEncoder.encode(user.getPassword());
        user.setPassword(encodedPassword);
    
        userRepository.save(user);
        return "register_success";
    }

    @GetMapping("/users")
    public String listUsers(Model model) {
        List<User> users = userRepository.findAll();
        model.addAttribute("users", users);
        return "list_users";
    }

    @GetMapping("/quotes")
    public String listQuotes(Model model) {
        List<Quote> quotes = quoteRepository.findAll();
        model.addAttribute("quotes", quotes);
        return "quotes/list_quotes";
    }

    @GetMapping("/showFormToAddQuote")
    public String showFormToAddQuote(Model model) {
        Quote quote = new Quote();
        model.addAttribute("quote", quote);
        return "quotes/add_quote";
    }

    @PostMapping("/processQuote")
    public String processQuote(@ModelAttribute("quote") Quote quote) {
        quoteRepository.save(quote);
        return "redirect:/quotes";
    }
}

User Class

@Entity
@Table(name="users")
public class User {

   @Id 
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name="id")
   private Long id;
 
   @Column(nullable = false, unique = true, length = 45)
   private String email;
 
   @Column(nullable = false, length = 64)
   private String password;
 
   @Column(name = "first_name", nullable = false, length = 20)
   private String firstName;
 
   @Column(name = "last_name", nullable = false, length = 20)
   private String lastName;

   public User() {}

   public User(Long id, String email, String password, String firstName, String lastName) {
       this.id = id;
       this.email = email;
       this.password = password;
       this.firstName = firstName;
       this.lastName = lastName;
   }

   // getters and setters                                                                                       
}

User Repository Class

public interface UserRepository extends JpaRepository<User, Long> {

    @Query("SELECT u FROM User u WHERE u.email = :email")
    public User findByEmail(@Param("email") String email);

}

Quote Class

@Entity
@Table(name="quote")
public class Quote {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    private int id;
    
    @Column(name="quote")
    private String quote;
    
    @Column(name="quotee")
    private String quotee;
    
    @Column(name="found_in")
    private String foundIn;
    
    public Quote() {}

    public Quote(int id, String quote, String quotee, String foundIn) {
        super();
        this.id = id;
        this.quote = quote;
        this.quotee = quotee;
        this.foundIn = foundIn;
    }

    // getters and setters  
}

Quote Repository Class

public interface QuoteRepository extends JpaRepository<Quote, Integer> {

}

Using Thymeleaf syntax for html forms:

List Quotes HTML

<div > 
    <table >
        <thead >
            <tr>
                <th>Quote</th>
                <th>Quotee</th>
                <th>Found In</th>
            </tr>
        </thead>
        <tbody>
            <tr th:each="quote: ${quotes}">
                <td th:text="${quote.quote}">Quote</td>
                <td th:text="${quote.quotee}">Quotee</td>
                <td th:text="${quote.foundIn}">Found In</td>
            </tr>
        </tbody>
    </table>
</div>

Add Quote Form HTML

<form th:action="@{/processQuote}" th:object="${quote}"
   method="POST" style="max-width: 600px; margin: 0 auto;">
            
   <input type="text" th:field="*{quote}"
       placeholder="Quote" required>
   <input type="text" th:field="*{quotee}"
       placeholder="Quotee">
   <input type="text" th:field="*{foundIn}"
       placeholder="Source (Found In)">
            
   <button type="submit" >Save</button>
</form>

I excluded imports, package names, and getters/setters. It seems that spring is trying to convert my string input corresponding to the 'quote' column of the table into an in Integer even though the field is of type String.

Stack Trace

There was an unexpected error (type=Bad Request, status=400).
Failed to convert value of type 'java.lang.String' to required type 'com.maria.springboot.quoterepo.entity.Quote'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Integer] for value 'Life isn't about finding yourself. Life is about creating yourself.'; nested exception is java.lang.NumberFormatException: For input string: "Lifeisn'taboutfindingyourself.Lifeisaboutcreatingyourself."
org.springframework.beans.TypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'com.maria.springboot.quoterepo.entity.Quote'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Integer] for value 'Life isn't about finding yourself. Life is about creating yourself.'; nested exception is java.lang.NumberFormatException: For input string: "Lifeisn'taboutfindingyourself.Lifeisaboutcreatingyourself."
    at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:79)
    at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:53)
    at org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java:700)
    at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.createAttributeFromRequestValue(ServletModelAttributeMethodProcessor.java:142)
    at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.createAttribute(ServletModelAttributeMethodProcessor.java:78)
    at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:147)
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:179)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:146)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter.doFilterInternal(DefaultLogoutPageGeneratingFilter.java:58)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:237)
    at org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:223)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:219)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:132)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:831)
Caused by: org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Integer] for value 'Life isn't about finding yourself. Life is about creating yourself.'; nested exception is java.lang.NumberFormatException: For input string: "Lifeisn'taboutfindingyourself.Lifeisaboutcreatingyourself."
    at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:47)
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:192)
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:175)
    at org.springframework.data.repository.support.DomainClassConverter$ToEntityConverter.convert(DomainClassConverter.java:176)
    at org.springframework.data.repository.support.DomainClassConverter.lambda$convert$0(DomainClassConverter.java:84)
    at java.base/java.util.Optional.map(Optional.java:260)
    at org.springframework.data.repository.support.DomainClassConverter.convert(DomainClassConverter.java:84)
    at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41)
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:192)
    at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:129)
    at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:73)
    ... 99 more
Caused by: java.lang.NumberFormatException: For input string: "Lifeisn'taboutfindingyourself.Lifeisaboutcreatingyourself."
    at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
    at java.base/java.lang.Integer.parseInt(Integer.java:660)
    at java.base/java.lang.Integer.valueOf(Integer.java:991)
    at org.springframework.util.NumberUtils.parseNumber(NumberUtils.java:211)
    at org.springframework.core.convert.support.StringToNumberConverterFactory$StringToNumber.convert(StringToNumberConverterFactory.java:64)
    at org.springframework.core.convert.support.StringToNumberConverterFactory$StringToNumber.convert(StringToNumberConverterFactory.java:50)
    at org.springframework.core.convert.support.GenericConversionService$ConverterFactoryAdapter.convert(GenericConversionService.java:437)
    at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41)
    ... 109 more

CodePudding user response:

Caused by: java.lang.NumberFormatException: For input string: "Lifeisn'taboutfindingyourself.Lifeisaboutcreatingyourself."
    at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
    at java.base/java.lang.Integer.parseInt(Integer.java:660)

This is the causing issue - it can't parse "Lifeisn'taboutfindingyourself.Lifeisaboutcreatingyourself." into an integer.

My guess is that it is happenning because you don't have a constructor for Quote that expects 3 Strings so Thymeleaf picks the one with all arguments including Id and tries to convert the first parameter into an Integer.

Try creating the right constructor:

public Quote(String quote, String quotee, String foundIn) {
    this.quote = quote;
    this.quotee = quotee;
    this.foundIn = foundIn;
}

Also make sure all the setters are also present - important for thymeleaf

CodePudding user response:

Use Wrapper type for your id property in Quote entity instead of primitives. As follows

@Entity
@Table(name="quote")
public class Quote {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    private Long id; // <--- Change from `int` to Long
...
...

}
  •  Tags:  
  • Related