728x90

문제 상황

400 Bad Request 가 나면서 지속적으로 망할놈의 Bad Request 만 발견되던 상황이였고, 이런 부분은 아래와 같이 해결할 수 있다. 

 

https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send

 

Method: projects.messages.send  |  Firebase Cloud Messaging REST API

 

firebase.google.com

 

이렇게 위의 해당하는 URL로 가게 되면 우측 창에 Payload 를 전개할 수 있는 창이 있는데, 해당하는 부분에 파라미터들을 추가하면서 실험해볼 수가 있다.

 


이걸 해결하기 전까지는 어떤 삽질들을 했을까?

1. Postman을 이용한 삽질

 

아래와 같이 Payload  를 정의한다.

 

POST 에 소스코드에서 추가했던 바처럼 message 의 send 를 보낼 수 있는 엔드포인트를 postman의 상단에 정의한다

POST https://fcm.googleapis.com/v1/projects/moyamo-plus/messages:send

 

 

Request Body 를 정의한다.

FCM HTTP v1 Payload 에서는 공통 부분을 정의할 때에는 (안드로이드와 iOS에 대해서 동시에 발송할 때에는) 반드시 message 하부에 notification 의 body가 정의되어야 한다. 

 

{
    "message":{
        "notification":{
            "title":"이름이 뭘까요?",
            "body":"알림테스트에 들어갑니다"
        },
        "token":"fG1sB-i_TRWsI1W9vjL0ql:APA91bFq8CvJ14HqaWDBDO7b4qNwk3avS4_RP849X-s801cIjXgRgfTHLULLpojpXI9tACW1hDmZEkINjXJpU6oh4y4YTIEm3k7LvYQO8Z0zOrkYEAIY1E3bbPtB77y3YhjALR0JF8XL",
        "android":{
            "notification":{
                "click_action":".MainActivity",
                "sound":"default"
            }
        }
    },
    "validate_only":false
}

 

 

android의 경우에는 notification 이 있고 title 과 body가 있을 경우 해당하는 속성을 override 해서 사용하므로 해당하는 부분만 참고하면 된다.

 

주의해야 할 부분에 대한 정의

1. Common Notification에 대한 Payload

FCM HTTP v1 Payload 에서는 공통 부분을 정의할 때에는 (안드로이드와 iOS에 대해서 동시에 발송할 때에는) 반드시 message 하부에 notification 의 body가 정의되어야 한다. 

 

 

2. Android Notification 과 Common Notification의 Conflict 

message의 common noficatication field 와 android 에서 해당하는 부분을 동시에 정의했을 경우 Push Notification 이 발송되었을 때, Android 내에서 Main Activity 로 가서 intent-filter 에 의해서 발동하는 clickAction 이 정상적으로 발동되지 않는다.

 

따라서 Main Activity 로 향하는 부분에 대한 정의만 필요하다면 굳이 Android 에 대한 부분을 정의하면서 최상단에 있는 Common Notification field 를 정의하진 말자

 

3. Custom Notication 에 대한 가능 여부

정확하게는 clickAction에 대한 유도라기 보다, Push Notification 에 대한 Custom Notification의 가능 여부는 당연히 가능하다.

 

모든 부분에 대한 사용 중에서 Data property 를 사용하면 되고, Payload 는 다음과 같이 전개하면 된다.

{
  "message": {
    "data": {
      "title": "<가을에 심는 구근> 알리움 2개 품종",
      "description": "test data close",
      "id": "15170295",
      "photoUrl": "",
      "referenceId": "15170295",
      "referenceType": "question",
      "resourceType": "question",
      "resourceId": "15170295"
    },
    "token": "fG1sB-i_TRWsI1W9vjL0ql:APA91bFq8CvJ14HqaWDBDO7b4qNwk3avS4_RP849X-s801cIjXgRgfTHLULLpojpXI9tACW1hDmZEkINjXJpU6oh4y4YTIEm3k7LvYQO8Z0zOrkYEAIY1E3bbPtB77y3YhjALR0JF8XL"
  },
  "validate_only": false
}

 

 

물론 이와같이 정의했을 경우 안드로이드에서 받아서 처리하는 Json에 대한 처리는 Android 내부에서 담당하게 되어있다.

728x90

문제 상황 요약

FCM 이 deprecated 되면서 2024년 6월 4일부로 완전히 종료되었다고 하지만 최종적으로 Firebase 내에서는 9월 4일날 완전히 공식 Support 가 종료된 것을 확인함.

 

결론 = 푸시 데이터 알림이 작동하지 않는다.

 

따라서 예전에 사용하던 FCM 에 대한 부분을 드러내고 FCM HTTP v1 을 강제적으로 사용해야 할 수 밖에 없는 상황에 놓으게 된다

 

중간 삽질

Firebase 에서 Cloud Function 이나 Google Cloud Console 에서 이것 저것을 실어서 product 를  가동중인 사용자라면 모를까 일반적인 사용자라면 해당하는 방법으로 가동되지 않는다. 따라서 Firebase 내에서 비공개 키 (private key) 에 관련된 json 파일을 받아서 importing 해야하고, 이 부부을 통해서 OAuth2 token 을 따다가 Credential token으로 넣어줘야 작동한다.

 

 

즉, 앱에서 푸시 알림을 보내려면 2가지의 토큰이 준비되어야 하는데

1. 앱 내에서 사용자마다 사용하는 push Token. 이 경우는 Firebase 에서 getInstance 에 의하여 토큰을 제공해주고, 해당 부분은 repository 에 정상적으로 저장되는 부분을 확인했다.

 

2. Bearer 로 Firebase와 연동해서 Oauth2 에 대한 토큰을 딴 뒤에 해당 부분을 통하여 키 인증을 해준다.

 

그럼에도 불구하고 아래와 같은 상황이 발생하는데

 


[Admin][2024-10-06 13:04:22][DEBUG][FcmPushModule.java][sendPushMsg(370)] : Send : {"message":{"notification":{"title":"아이리스(경기용인)님이 새 댓글을 남겼습니다.","body":"#가우라"},"token":"ePk90xxfSTKDpaKZQPC22_:APA91bF_4nVQWJgeX50szAta-VD6R1mXrKH552DIVPXQUuosdwSINXjd8PgIBd2_zpIKE4yjpSV5adUIqo50h0uhN_T-63_S2poVVQB9eFRivxZdiADLj0RqFxfnjZ1ycwZJefxKbQVl","android":{"notification":{"click_action":".MainActivity","sound":"default"}}},"validate_only":false}, topic null
[Admin][2024-10-06 13:04:22][DEBUG][FcmPushModule.java][sendPushMsg(390)] : Sending 'POST' request to URL : https://fcm.googleapis.com/v1/projects/moyamo-plus/messages:send
[Admin][2024-10-06 13:04:22][DEBUG][FcmPushModule.java][sendPushMsg(391)] : Post parameters : "{\"message\":{\"notification\":{\"title\":\"아이리스(경기용인)님이 새 댓글을 남겼습니다.\",\"body\":\"#가우라\"},\"token\":\"ePk90xxfSTKDpaKZQPC22_:APA91bF_4nVQWJgeX50szAta-VD6R1mXrKH552DIVPXQUuosdwSINXjd8PgIBd2_zpIKE4yjpSV5adUIqo50h0uhN_T-63_S2poVVQB9eFRivxZdiADLj0RqFxfnjZ1ycwZJefxKbQVl\",\"android\":{\"notification\":{\"click_action\":\".MainActivity\",\"sound\":\"default\"}}},\"validate_only\":false}"
[Admin][2024-10-06 13:04:22][ERROR][FcmPushModule.java][sendPushMsg(399)] : ChatPushModule
java.io.IOException: Server returned HTTP response code: 400 for URL: https://fcm.googleapis.com/v1/projects/moyamo-plus/messages:send
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1902)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1500)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:268)
        at net.infobank.moyamo.push.module.FcmPushModule.responseBodyLog(FcmPushModule.java:259)
        at net.infobank.moyamo.push.module.FcmPushModule.sendPushMsg(FcmPushModule.java:392)
        at net.infobank.moyamo.service.PushNotificationServiceImpl.lambda$sendRequest$0(PushNotificationServiceImpl.java:194)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:750)

 

대략 요약하자니 여러 부분에 있어서 Payload 구성이 잘못된 것이냐 아니냐에 대한 판단 1과 파라미터에 대한 판단 2가 이루어지는데, 코드를 뜯어보면서 본 결과로는 다음과 같다.

 

 

1. Android 에 실리는 Notification 에 대한 부분에서 data 에 대한 부분을 보낼 필요가 없을 경우에 맘대로 보내게 되면 신나게 에러를 뱉게 된다. 따라서 data : null 로 보내기 보다는, 실험한다고 해서 data : null로 보내지 말 것

 

2. Firebase 쪽에서 제공해주는 부분에 의해서 clickAction 과 click_action, validateOnly 와 validate_only  버전으로 두 개의 property 가 정상적으로 똑같이 Response 를 보내주고 있으나 references 에 있는 대로 validate_only 를 사용하는 것이 나을 것 같아 그렇게 사용하기로 했다.

 

그럼에도 불구하고 나오는 Bad Request 400 덕에 본능적으로 싸한 부분을 느끼고 여러 부분을 검토하다가

 

Firebase SDK 가 Google Cloud Messaging API 에 대한 role 을 가지고 있지 않을 것 같기에 확인하는 목적용으로 아래와 같이 role을 수정해주었다.

 

 

Service Account 를 확인한 뒤에 Google Cloud Console에서 "IAM & Admin." 을 찾아낸다

 

 

 

이후 아직 log에서 Bad Request 가 확인되지 않았기 때문에 Log 가 뜨면 또 확인해줘야한다 ^^...

 

여하튼 Issue Tracking 의 단계는 아래와 같았다.

 

  • Invalid FCM Token: Ensure the token "eK-yrDlcTrqwDKeBpRdldR:APA91bHjBPJfZuuGWQpQh0uAW2nf_2S-f5OF4nocBrgV9IRada4L609ftVKr8ocTChCaE5Bb6rTzH9LJcrL11ovOoLI9OPFhoFNWGWZMQW9B6Qmtio0wl4ZFrLGi3Om1kUu_wdoX_HFc" is valid and not expired or malformed.
  • Missing Permissions: Ensure your Firebase Cloud Messaging (FCM) API key and server credentials are correctly set up in your project.
  • Incorrect URL: Double-check that the request is being sent to the correct FCM endpoint (https://fcm.googleapis.com/v1/projects/{project_id}/messages:send).

첫번째로 확인사살한 부분은 FCM Token 에 대한 부분이고 이 부분은 당연히 작동했다. 

그 이후에 Missing Permission을 잡았고, Incorrect URL 에 대한 부분은 당연히 문제가 없는 부분인데 이래도 문제가 있으면 진짜 음..

 

728x90

Example Code

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .cors().configurationSource(request -> {
                    CorsConfiguration config = new CorsConfiguration();
                    config.setAllowedOrigins(Collections.singletonList("*")); // Allow localhost
                    config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
                    config.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type"));
                    config.setAllowCredentials(false);
                    return config;
                })
                .and()
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .httpBasic()
                .authenticationEntryPoint(customAuthenticationEntryPoint)
                .and()
                .exceptionHandling().accessDeniedHandler(customAccessDeniedHandler)
                .and()
                .authorizeRequests()
                .antMatchers("/signup").permitAll()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated();

        http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }

 

In example, setAllowCredentials method was seen "false". if want to set "setAllowedOrigins" method for asteroid, means '*', it need to be "false".

 

if not, will see next issue.

ev-api-1  | java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.
ev-api-1  | 	at org.springframework.web.cors.CorsConfiguration.validateAllowCredentials(CorsConfiguration.java:495) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.springframework.web.cors.CorsConfiguration.checkOrigin(CorsConfiguration.java:599) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.springframework.web.cors.DefaultCorsProcessor.checkOrigin(DefaultCorsProcessor.java:174) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.springframework.web.cors.DefaultCorsProcessor.handleInternal(DefaultCorsProcessor.java:116) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.springframework.web.cors.DefaultCorsProcessor.processRequest(DefaultCorsProcessor.java:95) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:87) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.11.jar!/:5.7.11]
ev-api-1  | 	at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) ~[spring-security-web-5.7.11.jar!/:5.7.11]
ev-api-1  | 	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) ~[spring-security-web-5.7.11.jar!/:5.7.11]
ev-api-1  | 	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.11.jar!/:5.7.11]
ev-api-1  | 	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:112) ~[spring-security-web-5.7.11.jar!/:5.7.11]
ev-api-1  | 	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:82) ~[spring-security-web-5.7.11.jar!/:5.7.11]
ev-api-1  | 	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.11.jar!/:5.7.11]
ev-api-1  | 	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) ~[spring-security-web-5.7.11.jar!/:5.7.11]
ev-api-1  | 	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.11.jar!/:5.7.11]
ev-api-1  | 	at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) ~[spring-security-web-5.7.11.jar!/:5.7.11]
ev-api-1  | 	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.11.jar!/:5.7.11]
ev-api-1  | 	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:221) ~[spring-security-web-5.7.11.jar!/:5.7.11]
ev-api-1  | 	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186) ~[spring-security-web-5.7.11.jar!/:5.7.11]
ev-api-1  | 	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.30.jar!/:5.3.30]
ev-api-1  | 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:168) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1790) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.80.jar!/:na]
ev-api-1  | 	at java.base/java.lang.Thread.run(Thread.java:840) ~[na:na]
728x90

Sometimes changes made to the model or to the ORM may not reflect accurately on the database even after an execution of SchemaUpdate.

If the error actually seems to lack a sensible explanation, try recreating the database (or at least creating a new one) and scaffolding it with SchemaExport.

 

2024-07-23 14:30:43.399  WARN 17560 --- [ault-executor-0] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 1364, SQLState: HY000
2024-07-23 14:30:43.399 ERROR 17560 --- [ault-executor-0] o.h.engine.jdbc.spi.SqlExceptionHelper   : Field 'objectid' doesn't have a default value
2024-07-23 14:30:43.407 ERROR 17560 --- [ault-executor-0] c.c.otp.service.impl.OtpMgrServiceImpl   : Error saving OTP Entity: 

org.springframework.orm.jpa.JpaSystemException: could not execute statement; nested exception is org.hibernate.exception.GenericJDBCException: could not execute statement
	at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:331) ~[spring-orm-5.3.27.jar:5.3.27]
	at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:233) ~[spring-orm-5.3.27.jar:5.3.27]
	at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:551) ~[spring-orm-5.3.27.jar:5.3.27]
	at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) ~[spring-tx-5.3.27.jar:5.3.27]
	at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) ~[spring-tx-5.3.27.jar:5.3.27]
	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:152) ~[spring-tx-5.3.27.jar:5.3.27]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.27.jar:5.3.27]
	at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174) ~[spring-data-jpa-2.7.12.jar:2.7.12]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.27.jar:5.3.27]
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.27.jar:5.3.27]
	at org.springframework.aop.framework.ReflectiveMe

 

종종 ORM 관련되서 맛탱이가 가는 경우가 있는데, 정상적으로 save method 를 실행하지 못하며 신기하게 에러를 뱉는 경우가 있다.

 

디버깅에서 잡고 찔러봐도 분명히 데이터는 들어가는데, 왜 default value를 저장하는지 모르겠다 하고.

결론은 Stack Overflow 에서처럼 테이블 드랍시키고 다시 만들면 쑤욱 하고 들어간다

 

https://stackoverflow.com/questions/804514/hibernate-field-id-doesnt-have-a-default-value

 

Hibernate: "Field 'id' doesn't have a default value"

I'm facing what I think is a simple problem with Hibernate, but can't solve it (Hibernate forums being unreachable certainly doesn't help). I have a simple class I'd like to persist, but keep gett...

stackoverflow.com

 

 

 

+ Recent posts