Why is Spring #ConstructorBinding not binding for Kotlin #ConfigurationProperties class? - spring

I have a Spring auto configuration library I'm developer for Swagger. It's written in Kotlin using Spring Boot 2.2.6.
My main auto configuration is defined as:
package io.opengood.autoconfig.swagger
import org.apache.commons.lang3.StringUtils
import org.slf4j.LoggerFactory.getLogger
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import springfox.documentation.builders.AuthorizationCodeGrantBuilder
import springfox.documentation.builders.OAuthBuilder
import springfox.documentation.builders.PathSelectors
import springfox.documentation.service.*
import springfox.documentation.spi.DocumentationType
import springfox.documentation.spi.service.contexts.SecurityContext
import springfox.documentation.spring.web.plugins.Docket
import springfox.documentation.swagger.web.SecurityConfiguration
import springfox.documentation.swagger.web.SecurityConfigurationBuilder
import springfox.documentation.swagger2.annotations.EnableSwagger2
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.sql.Date as SqlDate
import java.sql.Time as SqlTime
import java.util.Date as UtilDate
#Configuration
#ConditionalOnProperty("swagger.enabled")
#EnableConfigurationProperties(value = [SwaggerProperties::class, OAuth2Properties::class])
#EnableSwagger2
class SwaggerAutoConfiguration(
val swaggerProperties: SwaggerProperties = SwaggerProperties(),
val swaggerVersion: SwaggerVersion = DefaultSwaggerVersion(),
val oAuth2Properties: OAuth2Properties = OAuth2Properties()
) {
val paths = swaggerProperties.paths
.takeIf { !it.isNullOrEmpty() }
.let { it?.joinToString(",") } ?: SwaggerProperties.DEFAULT_PATH
val version = swaggerVersion.version
.takeIf { it.isNotBlank() } ?: swaggerProperties.version
val authUri = oAuth2Properties.resource.authorizationServerUri
.takeIf { it.isNotBlank() } ?: OAuth2Properties.DEFAULT_AUTH_URI
val tokenUri = oAuth2Properties.tokenUri
.takeIf { it.isNotBlank() } ?: OAuth2Properties.DEFAULT_TOKEN_URI
#Bean
fun productApi(): Docket {
log.info("Setup Swagger product configuration")
val productApi = Docket(DocumentationType.SWAGGER_2)
.groupName(swaggerProperties.groupName)
.directModelSubstitute(LocalDateTime::class.java, UtilDate::class.java)
.directModelSubstitute(LocalDate::class.java, SqlDate::class.java)
.directModelSubstitute(LocalTime::class.java, SqlTime::class.java)
.apiInfo(apiInfo())
.select()
.paths(PathSelectors.regex(paths))
.build()
if (oAuth2Properties.enabled && !authUri.contains("localhost")) {
productApi.securitySchemes(listOf(securitySchemes()))
productApi.securityContexts(listOf(securityContext()))
}
return productApi
}
#Bean
fun apiInfo(): ApiInfo {
log.info("Setup Swagger API configuration")
return ApiInfo(
swaggerProperties.title,
swaggerProperties.description,
version,
swaggerProperties.termsOfServiceUrl,
Contact(
swaggerProperties.contact.name,
swaggerProperties.contact.url,
swaggerProperties.contact.email),
swaggerProperties.license.type,
swaggerProperties.license.url,
listOf())
}
#Bean
#ConditionalOnProperty("swagger.security.oauth2.enabled")
fun securityInfo(): SecurityConfiguration {
log.info("Setup Swagger security configuration")
return if (OAuth2Properties.GrantType.CLIENT_CREDENTIALS == oAuth2Properties.grantType) {
SecurityConfigurationBuilder.builder()
.clientId(StringUtils.EMPTY)
.clientSecret(StringUtils.EMPTY)
.scopeSeparator(" ")
.build()
} else {
SecurityConfigurationBuilder.builder()
.useBasicAuthenticationWithAccessCodeGrant(true)
.build()
}
}
private fun securitySchemes(): SecurityScheme {
return if (OAuth2Properties.GrantType.CLIENT_CREDENTIALS == oAuth2Properties.grantType) {
OAuthBuilder()
.name(SECURITY_REFERENCE_NAME)
.grantTypes(listOf(ClientCredentialsGrant(authUri)))
.scopes(scopes())
.build()
} else {
OAuthBuilder()
.name(SECURITY_REFERENCE_NAME)
.grantTypes(listOf(AuthorizationCodeGrantBuilder()
.tokenEndpoint(TokenEndpoint(tokenUri, TOKEN_NAME))
.tokenRequestEndpoint(TokenRequestEndpoint(authUri, "", ""))
.build()))
.scopes(scopes())
.build()
}
}
private fun securityContext(): SecurityContext {
return SecurityContext.builder()
.securityReferences(listOf(SecurityReference(SECURITY_REFERENCE_NAME, scopes().toTypedArray())))
.forPaths(PathSelectors.regex(paths))
.build()
}
private fun scopes(): List<AuthorizationScope> {
return oAuth2Properties.client.scopes
.takeIf { it.isNotEmpty() }
.let { it?.values?.map { s -> AuthorizationScope(s, "") } }
?: emptyList()
}
companion object {
const val SECURITY_REFERENCE_NAME = "spring_oauth2"
const val TOKEN_NAME = "oauth2_token"
#Suppress("JAVA_CLASS_ON_COMPANION")
#JvmStatic
private val log = getLogger(javaClass.enclosingClass)
}
}
I have several classes, see main one below, that are injected into the above class as beans using #ConfigurationProperties. I wanted to use the new #ConstructorBinding to remove the ugly lateint var from my main auto config class.
package io.opengood.autoconfig.swagger
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.ConstructorBinding
#ConfigurationProperties(prefix = "swagger")
#ConstructorBinding
data class SwaggerProperties(
val enabled: Boolean = true,
val groupName: String = "",
val paths: List<String> = listOf(DEFAULT_PATH),
val title: String = "",
val description: String = "",
val version: String = "",
val termsOfServiceUrl: String = "",
val contact: Contact = Contact(),
val license: License = License()
) {
#ConstructorBinding
data class Contact(
val name: String = "",
val url: String = "",
val email: String = ""
)
#ConstructorBinding
data class License(
val type: String = "",
val url: String = ""
)
companion object {
const val DEFAULT_PATH = ".*"
}
}
Source code is stored in my GitHub repo at https://github.com/opengoodio/swagger-auto-configuration.
The main auto config project is under lib/src/main/kotlin/io/opengood/autoconfig/swagger.
I have another project test-app that has a test class test-app/src/test/kotlin/io/opengood/autoconfig/swagger/app called AccessSwaggerTest:
package io.opengood.autoconfig.swagger.app
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit.jupiter.SpringExtension
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
#SpringBootTest(classes = [SwaggerTestApplication::class])
#ExtendWith(SpringExtension::class)
#AutoConfigureMockMvc
class AccessSwaggerTest {
#Autowired
lateinit var mockMvc: MockMvc
#Test
fun `swagger UI endpoint is accessible`() {
mockMvc.perform(get("/swagger-ui.html"))
.andExpect(status().is2xxSuccessful)
.andReturn();
}
#Test
fun `swagger API docs endpoint is accessible`() {
mockMvc.perform(get("/v2/api-docs?group=test-group"))
.andExpect(status().is2xxSuccessful)
.andReturn();
}
}
If you run the first test, it fails with:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:123)
at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:244)
at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:98)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$5(ClassBasedTestDescriptor.java:337)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:342)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$6(ClassBasedTestDescriptor.java:337)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312)
at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735)
at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:336)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:259)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$2(ClassBasedTestDescriptor.java:252)
at java.base/java.util.Optional.orElseGet(Optional.java:369)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$3(ClassBasedTestDescriptor.java:251)
at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:29)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:106)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:105)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:69)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$1(NodeTestTask.java:107)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:107)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:75)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'io.opengood.autoconfig.swagger.OAuth2Properties': #EnableConfigurationProperties or #ConfigurationPropertiesScan must be used to add #ConstructorBinding type io.opengood.autoconfig.swagger.OAuth2Properties
at org.springframework.boot.context.properties.ConfigurationPropertiesBeanDefinitionValidator.validate(ConfigurationPropertiesBeanDefinitionValidator.java:66)
at org.springframework.boot.context.properties.ConfigurationPropertiesBeanDefinitionValidator.postProcessBeanFactory(ConfigurationPropertiesBeanDefinitionValidator.java:45)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:286)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:174)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:706)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:126)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
... 63 more
If I boot run the simple app, it fails with a similar error.
The main auto config has #EnableConfigurationProperties(value = [SwaggerProperties::class, OAuth2Properties::class]) as the error suggests but still fails. I tried the #ConfigurationPropertiesScan on the test-app main class but same error.
I have searched for solutions over the past few months and cannot find a solid reason why this is occurring.
What is causing the #ConstructorBinding to not bind correctly?

My guess is: Your #SpringBootApplication annotated class is in package io.opengood.autoconfig.swagger.app and it scans for components in this package an all sub-packages. Your configuration file in the lib is in package io.opengood.autoconfig.swagger and therefore it might not be scanned. So you have two options:
Change package of your #SpringBootApplication annotated class
Add scanBasePackages to #SpringBootApplication, i.e. #SpringBootApplication(scanBasePackages = {"io.opengood.autoconfig.swagger", io.opengood.autoconfig.swagger.app})

Related

Status expected:<200> but was:<404> in spring test while testing my spring boot test cases

I have created two test cases out that one was working fine. While testing for the "/account/accountNumber" endpoint, I got an error.
Below is my controller test cases:
package com. bank;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.apache.coyote.Response;
import org.junit.Assert;
import org.junit.Before;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import com.bank.model.Account;
import com.bank.model.Customer;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class CapstoneBankProjectApplicationTests {
#Autowired
private MockMvc mockMvc;
#Autowired
private WebApplicationContext context;
ObjectMapper objectMapper=new ObjectMapper();
#Before
public void setUp() {
mockMvc=MockMvcBuilders.webAppContextSetup(context).build();
}
#Test
public void testcreateAccount() throws Exception {
Customer customer=new Customer();
customer.setCustomerId(1);
customer.setCustomerName("Manasa");
Account account=new Account();
account.setAccountNumber(456);
account.setAccountType("savings");
account.setBalance(2000.0);
account.setCustomer(customer);
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
String JsonRequest=objectMapper.writeValueAsString(account);
MvcResult result=mockMvc.perform(post("/account").content(JsonRequest).contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(status().isCreated()).andReturn();
String resultContext=result.getResponse().getContentAsString();
Response response=objectMapper.readValue(resultContext,Response.class);
Assert.assertTrue(response.getStatus()==200);
}
#Test
public void testgetAccountById() throws Exception{
MvcResult result = mockMvc.perform(get("/account/accountNumber").contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(status().isOk()).andReturn();
String resultContext = result.getResponse().getContentAsString();
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
Response response = objectMapper.readValue(resultContext, Response.class);
Assert.assertTrue(response.getStatus() ==200);
}
}
is there anything wrong?
console result:
MockHttpServletRequest:
HTTP Method = GET
Request URI = /account/accountNumber
Parameters = {}
Headers = [Content-Type:"application/json;charset=UTF-8"]
Body = null
Session Attrs = {}
Handler:
Type = com.bank.controller.AccountController
Method = com.bank.controller.AccountController#getAccountById(int)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = org.springframework.web.method.annotation.MethodArgumentTypeMismatchException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 400
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
2022-03-21 13:20:40.698 INFO 8696 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2022-03-21 13:20:40.698 INFO 8696 --- [ionShutdownHook] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down'
2022-03-21 13:20:40.701 WARN 8696 --- [ionShutdownHook] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 90121, SQLState: 90121
2022-03-21 13:20:40.701 ERROR 8696 --- [ionShutdownHook] o.h.engine.jdbc.spi.SqlExceptionHelper : Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-200]
2022-03-21 13:20:40.704 WARN 8696 --- [ionShutdownHook] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 90121, SQLState: 90121
2022-03-21 13:20:40.705 ERROR 8696 --- [ionShutdownHook] o.h.engine.jdbc.spi.SqlExceptionHelper : Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-200]
2022-03-21 13:20:40.705 WARN 8696 --- [ionShutdownHook] o.s.b.f.support.DisposableBeanAdapter : Invocation of destroy method failed on bean with name 'entityManagerFactory': org.hibernate.exception.JDBCConnectionException: Unable to release JDBC Connection used for DDL execution
2022-03-21 13:20:40.706 INFO 8696 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2022-03-21 13:20:40.711 INFO 8696 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
this is Junit console result:
java.lang.AssertionError: Status expected:<200> but was:<400>
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:59)
at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:122)
at org.springframework.test.web.servlet.result.StatusResultMatchers.lambda$matcher$9(StatusResultMatchers.java:627)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:212)
at com.bank.CapstoneBankProjectApplicationTests.testgetAccountById(CapstoneBankProjectApplicationTests.java:78)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:95)
at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:91)
at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:60)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
this is my controller:
package com.bank.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.bank.model.Account;
import com.bank.service.AccountService;
import com.bank.Exception.ResourceNotFoundException;
#RestController
#RequestMapping("/account")
public class AccountController {
#Autowired
AccountService accountService;
#PostMapping
public ResponseEntity<?> createAccount(#RequestBody Account account) throws ResourceNotFoundException{
Account acc=accountService.accountCreate(account);
if(acc!=null) {
return new ResponseEntity<>(acc,HttpStatus.CREATED);
}else {
throw new ResourceNotFoundException("Account is not Created!!");
}
}
#GetMapping("/aclist")
public ResponseEntity<?> accountList() throws ResourceNotFoundException{
List<Account> accountList=accountService.allAccounts();
if(!(accountList.isEmpty())) {
return new ResponseEntity<>(accountList,HttpStatus.OK);
}else {
throw new ResourceNotFoundException("accounts not found");
}
}
#GetMapping("/byType/{accountType}")
public ResponseEntity<?> byAccountType(#PathVariable String accountType) throws ResourceNotFoundException{
List<Account> account =accountService.accountByType(accountType);
if(account.isEmpty()) {
throw new ResourceNotFoundException(accountType+""+"Type of account does not exist!!");
}else {
return new ResponseEntity<>(account,HttpStatus.OK);
}
}
#GetMapping("/{accountNumber}")
public ResponseEntity<?> getAccountById(#PathVariable("accountNumber") int accountNumber) throws ResourceNotFoundException{
Account acc=accountService.findAccountById(accountNumber);
if(acc!=null) {
return new ResponseEntity<>(acc,HttpStatus.OK);
}else {
throw new ResourceNotFoundException("account [accountNumber="+accountNumber+"] can't be found");
}
}
#PutMapping("/{from}/{to}/{amount}")
public ResponseEntity<?> transferFunds(#PathVariable("from") int from,#PathVariable("to") int to,#PathVariable("amount") double amount) throws ResourceNotFoundException{
return accountService.transferFunds(from, to, amount);
}
#DeleteMapping("/{accountNumber}")
public ResponseEntity<?> deleteAccById(#PathVariable ("accountNumber") int accountNumber) throws ResourceNotFoundException{
String x=accountService.deleteById(accountNumber);
if(x.equalsIgnoreCase("deleted")){
return new ResponseEntity<>("deleted successfully",HttpStatus.OK);
}else {
throw new ResourceNotFoundException("Account [accountNumber="+accountNumber+"] can't be found");
}
}
#GetMapping("/balance/{accountNumber}")
public ResponseEntity<?> getBalanceById(#PathVariable ("accountNumber") int accountNumber) throws ResourceNotFoundException{
String balance=accountService.getBalanceById(accountNumber);
if(balance.equalsIgnoreCase("Invalid accountNumber")) {
throw new ResourceNotFoundException("Account [accountNumber="+accountNumber+"] can't be found");
}else {
return new ResponseEntity<>(balance,HttpStatus.OK);
}
}
#DeleteMapping("/deleteAll")
public ResponseEntity<?> deleteAllAccounts(){
return new ResponseEntity<>(accountService.deleteAllAccounts(),HttpStatus.OK);
}
#PutMapping("/update/{accountNumber}")
public ResponseEntity<?> UpdateAccount(#PathVariable ("accountNumber") int accountNumber,#RequestBody Account account) throws ResourceNotFoundException{
Account acc=accountService.updateAccount(accountNumber, account);
if(acc!=null) {
return new ResponseEntity<>(acc,HttpStatus.OK);
}else {
throw new ResourceNotFoundException("invalid accountNumber and account");
}
}
#PutMapping("/deposite/{amount}/{accountNumber}")
public ResponseEntity<?> deposite(#PathVariable("amount") double amount,#PathVariable("accountNumber") int accountNumber) throws ResourceNotFoundException{
return accountService.deposite(amount,accountNumber);
}
#PutMapping("/withdraw/{amount}/{accountNumber}")
public ResponseEntity<?> withDraw(#PathVariable("amount") double amount,#PathVariable("accountNumber") int accountNumber) throws ResourceNotFoundException{
return accountService.withdraw(amount,accountNumber);
}
}
for me Assert.asserTrue(response.isStatus()==Boolean.True) was not supporting so I used Assert.assertTrue(response.getStatus() ==200)
The HTTP 400 response indicates a bad request. Your HTTP GET endpoint expects an int while you're sending a String as the path variable.
So accountNumber must be a real number like 123:
MvcResult result = mockMvc
.perform(get("/account/123")
.contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(status().isOk())
.andReturn();

Spring data crud repository save method not able to save Java model in Redis cache

We are trying to save a model into the Redis cache using the spring data crud repository. This model has one property which is a map like below.
private Map<String, StudentInfo> studentData = new HashMap<String, StudentInfo>();
And this StudentInfo model has another Map as a property as below:-
private Map<String, Set<Books>> stBooks = new HashMap<String, Set<Books>>();
So overall structure is like this:-
Student.java
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
#JsonRootName(value = "student")
#JsonInclude(Include.NON_NULL)
public class Student implements Serializable {
private static final long serialVersionUID = -2421290151039598746L;
private Map<String, StudentInfo> studentData = new HashMap<String, StudentInfo>();
#JsonCreator
public Student(#JsonProperty("studentData") Map<String, StudentInfo> aStudentData)
{
super();
this.setStudentData(aStudentData);
}
public void studentData(String aId, StudentInfo astudentData)
{
this.studentData.put(aId, astudentData);
}
public Map<String, StudentInfo> getStudentData()
{
return this.studentData;
}
private void setStudentData(Map<String, StudentInfo> aStudentData)
{
this.studentData = aStudentData;
}}
StudentInfo.java
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
#JsonRootName(value = "studentInfo")
#JsonInclude(Include.NON_NULL)
public class StudentInfo implements Serializable {
private static final long serialVersionUID = 6873987079436896955L;
String stName = null;;
private Map<String, Set<Books>> stBooks = new HashMap<String, Set<Books>>();
public StudentInfo(String stName)
{
super();
this.setDealerCode(stName);
}
#JsonCreator
public StudentInfo(#JsonProperty("stName") String aStName,
#JsonProperty("stBooks") Map<String, Set<Books>> aStBooks)
{
super();
this.setDealerCode(aStName);
this.setStBooks(aStBooks);
}
private void setStBooks(Map<String, Set<Books>> aStBooks)
{
this.stBooks = aStBooks;
}
public Map<String, Set<Books>> getStBooks()
{
return this.stBooks;
}
private void setDealerCode(String astName)
{
this.stName = astName;
}
public String getStName()
{
return this.stName;
}
#Override
public String toString() {
return "Student [StudentName=" + stName + "]";
}}
Books.java
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
#JsonRootName(value = "books")
#JsonInclude(Include.NON_NULL)
public class Books implements Serializable {
private static final long serialVersionUID = 1759477433483466736L;
private String bookName = null;
#JsonCreator
public Books(#JsonProperty("bookName") String aBookName)
{
super();
this.setBookName(aBookName);
}
public String getBookName() {
return bookName;
}
private void setBookName(String aBookName) {
this.bookName = aBookName;
}
public String toString()
{
return this.getBookName();
}}
StudenCacheModel.java
import java.io.Serializable;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import lombok.Getter;
import lombok.Setter;
#Getter
#Setter
#RedisHash(value = "StudentCache")
public class StudenCacheModel implements Serializable {
private static final long serialVersionUID = 9174813592532123048L;
#Id
String userId;
Student student;
}
Spring Crud Repository
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface StudenCacheRepository extends CrudRepository<StudenCacheModel, String> {
}
Saving the model using Crud Repo
StudenCacheModel studentCacheModel = new StudenCacheModel();
studentCacheModel.setSrudent(st); //student model set
studentCacheModel.setUserId(userId);
studentCacheRepository.save(studentCacheModel);
Exception:-
enter code hereorg.springframework.data.mapping.MappingException: Couldn't find
PersistentEntity for type class java.lang.Object!
Complete Stacktrace:-
org.springframework.data.mapping.MappingException: Couldn't find PersistentEntity for type class java.lang.Object!
at org.springframework.data.mapping.context.MappingContext.getRequiredPersistentEntity(MappingContext.java:79) ~[spring-data-commons-2.6.1.jar:2.6.1]
at org.springframework.data.redis.core.convert.MappingRedisConverter.writeInternal(MappingRedisConverter.java:621) ~[spring-data-redis-2.6.1.jar:2.6.1]
at org.springframework.data.redis.core.convert.MappingRedisConverter.writeMap(MappingRedisConverter.java:867) ~[spring-data-redis-2.6.1.jar:2.6.1]
at org.springframework.data.redis.core.convert.MappingRedisConverter.lambda$writeInternal$2(MappingRedisConverter.java:640) ~[spring-data-redis-2.6.1.jar:2.6.1]
at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:360) ~[spring-data-commons-2.6.1.jar:2.6.1]
at org.springframework.data.redis.core.convert.MappingRedisConverter.writeInternal(MappingRedisConverter.java:624) ~[spring-data-redis-2.6.1.jar:2.6.1]
at org.springframework.data.redis.core.convert.MappingRedisConverter.writeMap(MappingRedisConverter.java:867) ~[spring-data-redis-2.6.1.jar:2.6.1]
at org.springframework.data.redis.core.convert.MappingRedisConverter.lambda$writeInternal$2(MappingRedisConverter.java:640) ~[spring-data-redis-2.6.1.jar:2.6.1]
at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:360) ~[spring-data-commons-2.6.1.jar:2.6.1]
at org.springframework.data.redis.core.convert.MappingRedisConverter.writeInternal(MappingRedisConverter.java:624) ~[spring-data-redis-2.6.1.jar:2.6.1]
at org.springframework.data.redis.core.convert.MappingRedisConverter.writeMap(MappingRedisConverter.java:867) ~[spring-data-redis-2.6.1.jar:2.6.1]
at org.springframework.data.redis.core.convert.MappingRedisConverter.lambda$writeInternal$2(MappingRedisConverter.java:640) ~[spring-data-redis-2.6.1.jar:2.6.1]
at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:360) ~[spring-data-commons-2.6.1.jar:2.6.1]
at org.springframework.data.redis.core.convert.MappingRedisConverter.writeInternal(MappingRedisConverter.java:624) ~[spring-data-redis-2.6.1.jar:2.6.1]
at org.springframework.data.redis.core.convert.MappingRedisConverter.lambda$writeInternal$2(MappingRedisConverter.java:666) ~[spring-data-redis-2.6.1.jar:2.6.1]
at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:360) ~[spring-data-commons-2.6.1.jar:2.6.1]
at org.springframework.data.redis.core.convert.MappingRedisConverter.writeInternal(MappingRedisConverter.java:624) ~[spring-data-redis-2.6.1.jar:2.6.1]
at org.springframework.data.redis.core.convert.MappingRedisConverter.write(MappingRedisConverter.java:424) ~[spring-data-redis-2.6.1.jar:2.6.1]
at org.springframework.data.redis.core.convert.MappingRedisConverter.write(MappingRedisConverter.java:114) ~[spring-data-redis-2.6.1.jar:2.6.1]
at org.springframework.data.redis.core.RedisKeyValueAdapter.put(RedisKeyValueAdapter.java:215) ~[spring-data-redis-2.6.1.jar:2.6.1]
at org.springframework.data.keyvalue.core.KeyValueTemplate.lambda$update$1(KeyValueTemplate.java:221) ~[spring-data-keyvalue-2.6.1.jar:2.6.1]
at org.springframework.data.keyvalue.core.KeyValueTemplate.execute(KeyValueTemplate.java:362) ~[spring-data-keyvalue-2.6.1.jar:2.6.1]
at org.springframework.data.keyvalue.core.KeyValueTemplate.update(KeyValueTemplate.java:221) ~[spring-data-keyvalue-2.6.1.jar:2.6.1]
at org.springframework.data.redis.core.RedisKeyValueTemplate.update(RedisKeyValueTemplate.java:178) ~[spring-data-redis-2.6.1.jar:2.6.1]
at org.springframework.data.keyvalue.repository.support.SimpleKeyValueRepository.save(SimpleKeyValueRepository.java:80) ~[spring-data-keyvalue-2.6.1.jar:2.6.1]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:289) ~[spring-data-commons-2.6.1.jar:2.6.1]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137) ~[spring-data-commons-2.6.1.jar:2.6.1]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121) ~[spring-data-commons-2.6.1.jar:2.6.1]
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:529) ~[spring-data-commons-2.6.1.jar:2.6.1]
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285) ~[spring-data-commons-2.6.1.jar:2.6.1]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:639) ~[spring-data-commons-2.6.1.jar:2.6.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:163) ~[spring-data-commons-2.6.1.jar:2.6.1]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:138) ~[spring-data-commons-2.6.1.jar:2.6.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.15.jar:5.3.15]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.15.jar:5.3.15]
at com.sun.proxy.$Proxy163.save(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.15.jar:5.3.15]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.15.jar:5.3.15]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.15.jar:5.3.15]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-5.3.15.jar:5.3.15]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.15.jar:5.3.15]
at com.sun.proxy.$Proxy163.save(Unknown Source) ~[na:na]
Q1 - Is it the limitation of Spring data redis as we are able to save the same model using JEDIS library.
Any help/input will be highly apperciated !!
With a few small changes I got your example working:
In the POM used Spring Boot 2.6.4 and Java 11:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
Added a no-args constructor to StudentInfo
Added Lombok #ToString1 to StudenCacheModel
Modified Student to have method params that Jackson reflection could use:
#JsonRootName(value = "student")
#JsonInclude(Include.NON_NULL)
public class Student implements Serializable {
private static final long serialVersionUID = -2421290151039598746L;
private Map<String, StudentInfo> studentData = new HashMap<String, StudentInfo>();
#JsonCreator
public Student(#JsonProperty("studentData") Map<String, StudentInfo> studentData) {
super();
this.setStudentData(studentData);
}
public void studentData(String aId, StudentInfo studentData) {
this.studentData.put(aId, studentData);
}
public Map<String, StudentInfo> getStudentData() {
return this.studentData;
}
private void setStudentData(Map<String, StudentInfo> studentData) {
this.studentData = studentData;
}
}
Added a simple test with a runner on the main app:
#SpringBootApplication
public class SodemoApplication {
#Bean
CommandLineRunner testRepo(StudenCacheRepository studentCacheRepository) {
return args -> {
StudenCacheModel studentCacheModel = new StudenCacheModel();
StudentInfo si = new StudentInfo("bsb");
Student st = new Student(Map.of("bsb", si));
studentCacheModel.setStudent(st); //student model set
studentCacheRepository.save(studentCacheModel);
studentCacheRepository.findAll().forEach(System.out::println);
};
}
public static void main(String[] args) {
SpringApplication.run(SodemoApplication.class, args);
}
}
Running it you get the console output:
[2m2022-03-09 10:07:19.087[0;39m [32m INFO[0;39m [35m19669[0;39m [2m---[0;39m [2m[ main][0;39m [36mcom.example.sodemo.SodemoApplication [0;39m [2m:[0;39m Started SodemoApplication in 1.134 seconds (JVM running for 1.734)
StudenCacheModel(userId=19028f97-3e10-4776-8777-4a8cee224baf, student=com.example.sodemo.Student#24e5389c)
And on the Redis CLI you can see:
127.0.0.1:6379> keys *
1) "StudentCache"
2) "StudentCache:19028f97-3e10-4776-8777-4a8cee224baf"
127.0.0.1:6379> TYPE "StudentCache:19028f97-3e10-4776-8777-4a8cee224baf"
hash
127.0.0.1:6379> HGETALL "StudentCache:19028f97-3e10-4776-8777-4a8cee224baf"
1) "_class"
2) "com.example.sodemo.StudenCacheModel"
3) "student.studentData.[bsb].stName"
4) "bsb"
5) "userId"
6) "19028f97-3e10-4776-8777-4a8cee224baf"
127.0.0.1:6379>
I've created a repo with the full running example at https://github.com/bsbodden/sodemo
BTW Spring Data Redis uses Lettuce by default unless you configure it to use Jedis; both drivers can be used to save #RedisHash annotated entities

java.lang.NullPointerException what I'm doing wrong?

I'm working on a project in which my intention is to run a Corn job and send mail to my friends to wishing them on their birthday, I was able to get email from MySQL DB and compared it to the current date but when it comes to sending an email I'm getting NullPointerException.
I'm sure there is no problem with application properties I used them with other projects as well and they are function properly
//Imports
package dev.teja.happybirthday;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.*;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.persistence.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.validation.constraints.Email;
import freemarker.template.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.bind.annotation.*;
//Main
#SpringBootApplication
public class HappybirthdayApplication {
public static void main(String[] args) {
SpringApplication.run(HappybirthdayApplication.class, args);
}
#Autowired
MyFriendsRepository myFriendsRepository ;
#Scheduled(cron = "*/30 * * * * *")
void WishMyFriends() {
List<MyFriends> myFriendsList = myFriendsRepository.findAll();
myFriendsList.forEach(friend -> {
Date date = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("dd/MM");
String CurrentDate= formatter.format(date);
String GivenDate = formatter.format(friend.dob);
if (GivenDate.equals(CurrentDate)){
Job job = new Job();
Map<String, Object> model = new HashMap<>();
model.put("Name",friend.name);
job.sendWish(friend.email,model);
}
});
}
}
#Configuration
#ConditionalOnProperty(name = "scheduling.enabled", matchIfMissing = true)
#EnableScheduling
class Tasks {
}
//Model
#Data
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
#ToString
#Entity
class MyFriends {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
String name;
#Email
#Column(unique = true)
String email;
#JsonFormat(pattern = "dd/MM/yyyy", shape = JsonFormat.Shape.STRING)
Date dob;
Long phoneNumber;
}
//Repository
interface MyFriendsRepository extends JpaRepository<MyFriends, Long> {
}
#RestController
#RequestMapping("/")
class FriendsController {
#Autowired
MyFriendsRepository myFriendsRepository;
#PostMapping("/friends")
ResponseEntity<MyFriends> createFriend(#RequestBody MyFriends myFriend) {
myFriendsRepository.save(myFriend);
return new ResponseEntity<MyFriends>(myFriend, HttpStatus.CREATED);
}
#GetMapping("/friends")
List<MyFriends> getFriends() {
return myFriendsRepository.findAll();
}
}
//Interface
interface wisher{
void sendWish(String email, Map<String, Object> model);
}
//Implementation
#Service
class Job implements wisher{
#Autowired
private JavaMailSender sender;
#Autowired
private freemarker.template.Configuration config;
#Override
public void sendWish(String email,Map<String, Object> model) {
System.out.println("wishes sent to "+ email);
MimeMessage message = sender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED,
StandardCharsets.UTF_8.name());
Template template = config.getTemplate("new-template.ftl");
String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
helper.setTo(email);
helper.setFrom("kondasaitej#gmail.com");
helper.setSubject("Happy Birthday");
helper.setText(html,true);
sender.send(message);
} catch (MessagingException | IOException | TemplateException e) {
e.printStackTrace();
}
}
}
FreeMaker file in ./resources/Templates
/**
* FREEMAKER new-template.ftl
* <html xmlns="http://www.w3.org/1999/xhtml">
* <head>
* <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
* <title>Comment Alert Mail</title>
* </head>
* <body>
* <p>happy birthday ${Name}</p>
* </body>
*/
This is the error I'm getting this following
Hibernate: select myfriends0_.id as id1_0_, myfriends0_.dob as dob2_0_, myfriends0_.email as email3_0_, myfriends0_.name as name4_0_, myfriends0_.phone_number as phone_nu5_0_ from my_friends myfriends0_
wishes sent to kondasaitej#protonmail.com
2020-09-26 21:01:52.012 ERROR 84242 --- [ scheduling-1] o.s.s.s.TaskUtils$LoggingErrorHandler : Unexpected error occurred in scheduled task
java.lang.NullPointerException: null
at dev.teja.happybirthday.Job.sendWish(HappybirthdayApplication.java:115) ~[classes/:na]
at dev.teja.happybirthday.HappybirthdayApplication.lambda$WishMyFriends$0(HappybirthdayApplication.java:53) ~[classes/:na]
at java.util.ArrayList.forEach(ArrayList.java:1257) ~[na:1.8.0_251]
at dev.teja.happybirthday.HappybirthdayApplication.WishMyFriends(HappybirthdayApplication.java:44) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_251]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_251]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_251]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_251]
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:93) [spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_251]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_251]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_251]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_251]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_251]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_251]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_251]
Try add getting in the #Autowired private JavaMailSender sender;
I think you have not implemented your JavaMailSender bean. Define a bean like below. Then your #Autowire annotation will work.
#Bean
public JavaMailSender getJavaMailSender()
{
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost("smtp.gmail.com");
mailSender.setPort(25);
mailSender.setUsername("admin#gmail.com");
mailSender.setPassword("password");
Properties props = mailSender.getJavaMailProperties();
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.debug", "true");
return mailSender;
}

Unhandled async exception in Resource with Server-Sent Event RESTEasy + Spring Integracion

The Task: The API is built using JAX-RS RESTEasy and Spring(RESTEasy-Spring Dependency) in order to enable API to use Spring dependency injection features, and also . Here everything is working fine. Then, In a resource there is a method to send messages from a server to the client in real-time(Server-Sent Event). I took this code(enter link description here) to build the method, but in the example EJB is used and some concurrency annotation defined there(#Singleton, #LOCK, LockType.{READ,WRITE}).
The Problem: When I consume that method the server throw the following exception:
20:15:29,669 ERROR [org.jboss.resteasy.resteasy_jaxrs.i18n] (default task-1) RESTEASY002020: Unhandled asynchronous exception, sending back 500: org.jboss.resteasy.spi.UnhandledException: java.lang.NullPointerException
I guest the problem is related to concurrency. First, the application was standalone(RUNNING ON JETTY), then it was deployed on wildfly application server in order to use EJB features and replicate the same example. However, due to the fact I use RESTEasy + Spring the resource(JAX-RS Resource) has to be annotated with #Component and managed by Spring Container. I tried to replace that with EJB #Singleton annotation and use #Lock() annotation in the methods as well, but when that is done the resource is not found(not deploy). I guest it is required the resource to be annotated with #Component in order to get this integration(RESTEasy + Spring) working. I searched about concurrency with Java SE and made use of the following package java.util.concurrent.locks but with no success.
These are my interface and class:
package edu.cibertec.votoelectronico.resource;
import java.io.IOException;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.sse.SseEventSink;
import org.springframework.context.event.EventListener;
import edu.cibertec.votoelectronico.application.event.EmitirVotoEvent;
#Path("/votoelectronico/subscribe")
public interface SSEVotoElectronicoResource {
#GET
#Lock(LockType.READ)
#Path("/resultado")
#Produces(MediaType.SERVER_SENT_EVENTS)
public void obtenerResultados(#HeaderParam(HttpHeaders.LAST_EVENT_ID_HEADER) #DefaultValue("-1") int lastEventId,
#Context SseEventSink eventSink) throws IOException;
#Lock(LockType.WRITE)
#EventListener
public void onEmitirVotoEvent(EmitirVotoEvent domainEvent);
#GET
#Path("/")
#Produces(MediaType.APPLICATION_JSON)
public Response test();
}
package edu.cibertec.votoelectronico.resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
//import javax.ejb.Lock;
//import javax.ejb.LockType;
//import javax.ejb.Singleton;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.sse.OutboundSseEvent;
import javax.ws.rs.sse.Sse;
import javax.ws.rs.sse.SseBroadcaster;
import javax.ws.rs.sse.SseEventSink;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import edu.cibertec.votoelectronico.application.event.EmitirVotoEvent;
import edu.cibertec.votoelectronico.domain.complex.VotoResumen;
import edu.cibertec.votoelectronico.dto.VotoResumenDto;
import edu.cibertec.votoelectronico.mapping.MapperFactoryRegistry;
import edu.cibertec.votoelectronico.resource.communication.BaseResponse;
import edu.cibertec.votoelectronico.resource.communication.ResumenProcesoResponse;
import edu.cibertec.votoelectronico.service.VotoService;
//#Singleton
#Path("/votoelectronico/subscribe")
#Component
public class SimpleSSEVotoElectronicoResource implements SSEVotoElectronicoResource {
private final Logger LOG = LoggerFactory.getLogger(SimpleSSEVotoElectronicoResource.class);
private Sse sse;
private final Lock readLock;
private final Lock writeLock;
#Autowired
private VotoService service;
#Autowired
private MapperFactoryRegistry mapper;
private SseBroadcaster sseBroadcaster;
private int lastEventId;
private final List<ResumenProcesoResponse> messages = new ArrayList<ResumenProcesoResponse>();
public SimpleSSEVotoElectronicoResource() {
ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
this.readLock = readWriteLock.readLock();
this.writeLock = readWriteLock.writeLock();
}
#PostConstruct
public void init() {
LOG.info("On Init method...");
}
#Context
public void setSse(Sse sse) {
this.sse = sse;
this.sseBroadcaster = this.sse.newBroadcaster();
this.sseBroadcaster.onError((o, e) -> {
LOG.error("Ocurred an error on broadcasting: ", e);
});
this.sseBroadcaster.onClose((eventSink) -> {
LOG.info("Broadcast closed: ", eventSink);
});
}
#Override
// #Lock(LockType.READ)
public void obtenerResultados(int lastEventId, SseEventSink eventSink) throws IOException {
readLock.lock();
try {
if (lastEventId >= 0)
this.replyLastMessage(lastEventId, eventSink);
sseBroadcaster.register(eventSink);
LOG.info("Client has being registered");
} finally {
readLock.unlock();
}
}
#Override
// #Lock(LockType.WRITE)
public void onEmitirVotoEvent(EmitirVotoEvent domainEvent) {
writeLock.lock();
try {
LOG.info("EmitirVoto Event received");
ResumenProcesoResponse response = this.fetchResumenProceso();
this.messages.add(response);
OutboundSseEvent event = createEvent(response, ++this.lastEventId);
LOG.info("Server about to send Event");
this.sseBroadcaster.broadcast(event);
} finally {
writeLock.unlock();
}
}
private void replyLastMessage(int lastEventId, SseEventSink eventSink) {
try {
for (int i = lastEventId; i < messages.size(); i++) {
eventSink.send(createEvent(messages.get(i), i + 1));
}
} catch (Exception e) {
throw new InternalServerErrorException("Could not reply messages ", e);
}
}
private ResumenProcesoResponse fetchResumenProceso() {
ResumenProcesoResponse response = null;
try {
LOG.info("Fetching proccess resume..");
Collection<VotoResumen> resultados = this.service.results();
Function<VotoResumen, VotoResumenDto> convert = (VotoResumen object) -> this.mapper.convertFrom(object,
VotoResumenDto.class);
Collection<VotoResumenDto> collection = resultados.stream().map(convert).collect(Collectors.toList());
response = new ResumenProcesoResponse(collection);
} catch (Exception e) {
LOG.error("Ocurred an error while trying to get resume. " + e.getMessage());
response = new ResumenProcesoResponse(e.getMessage());
}
return response;
}
private OutboundSseEvent createEvent(ResumenProcesoResponse response, int id) {
return this.sse.newEventBuilder().id(String.valueOf(id)).data(response).build();
}
#Override
public Response test() {
try {
return Response.status(Response.Status.OK).entity(new BaseResponse(true, "")).build();
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(new BaseResponse(false, e.toString()))
.build();
}
}
}
Full error description:
20:15:29,669 ERROR [org.jboss.resteasy.resteasy_jaxrs.i18n] (default task-1) RESTEASY002020: Unhandled asynchronous exception, sending back 500: org.jboss.resteasy.spi.UnhandledException: java.lang.NullPointerException
at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:82)
at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:346)
at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:193)
at org.jboss.resteasy.core.SynchronousDispatcher.asynchronousExceptionDelivery(SynchronousDispatcher.java:510)
at org.jboss.resteasy.core.AbstractAsynchronousResponse.internalResume(AbstractAsynchronousResponse.java:232)
at org.jboss.resteasy.plugins.server.servlet.Servlet3AsyncHttpRequest$Servlet3ExecutionContext$Servle3AsychronousResponse.resume(Servlet3AsyncHttpRequest.java:117)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:431)
at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$0(ResourceMethodInvoker.java:370)
at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:356)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:372)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:344)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:317)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:440)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:229)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:135)
at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:356)
at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:138)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:215)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:227)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
at io.opentracing.contrib.jaxrs2.server.SpanFinishingFilter.doFilter(SpanFinishingFilter.java:52)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269)
at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1504)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1504)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1504)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1504)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1504)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:376)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1982)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException
at edu.cibertec.votoelectronico.resource.SimpleSSEVotoElectronicoResource.obtenerResultados(SimpleSSEVotoElectronicoResource.java:90)
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.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:138)
at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:517)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:406)
... 63 more
Example code:
package com.example.sse.boundary;
import com.example.sse.entity.DomainEvent;
import javax.annotation.PostConstruct;
import javax.ejb.Lock;
import javax.ejb.Singleton;
import javax.enterprise.event.Observes;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.sse.OutboundSseEvent;
import javax.ws.rs.sse.Sse;
import javax.ws.rs.sse.SseBroadcaster;
import javax.ws.rs.sse.SseEventSink;
import java.util.ArrayList;
import java.util.List;
import static javax.ejb.LockType.READ;
import static javax.ejb.LockType.WRITE;
#Path("events-examples")
#Singleton
public class EventsResource {
#Context
Sse sse;
private SseBroadcaster sseBroadcaster;
private int lastEventId;
private List<String> messages = new ArrayList<>();
#PostConstruct
public void initSse() {
sseBroadcaster = sse.newBroadcaster();
sseBroadcaster.onError((o, e) -> {
// ...
});
}
#GET
#Lock(READ)
#Produces(MediaType.SERVER_SENT_EVENTS)
public void itemEvents(#HeaderParam(HttpHeaders.LAST_EVENT_ID_HEADER)
#DefaultValue("-1") int lastEventId,
#Context SseEventSink eventSink) {
if (lastEventId >= 0)
replayLastMessages(lastEventId, eventSink);
sseBroadcaster.register(eventSink);
}
private void replayLastMessages(int lastEventId, SseEventSink eventSink) {
try {
for (int i = lastEventId; i < messages.size(); i++) {
eventSink.send(createEvent(messages.get(i), i + 1));
}
} catch (Exception e) {
throw new InternalServerErrorException("Could not replay messages ", e);
}
}
private OutboundSseEvent createEvent(String message, int id) {
return sse.newEventBuilder().id(String.valueOf(id)).data(message).build();
}
#Lock(WRITE)
public void onEvent(#Observes DomainEvent domainEvent) {
String message = domainEvent.getContents();
messages.add(message);
OutboundSseEvent event = createEvent(message, ++lastEventId);
sseBroadcaster.broadcast(event);
}
}
The source code is here: enter link description here
I tried to catch the error but with no success.
Can you please help me out to solve this error or give some advices.

at org.hibernate.hql.internal.ast.QuerySyntaxException.generateQueryException: model class is not mapped

I am new to SpringBoot. I am writing a project in SpringBoot(along with Hibernate)
while accessing the database, I am getting following error:
org.hibernate.hql.internal.ast.QuerySyntaxException: HashMapping is not mapped [from HashMapping where consumerUserId=:consumerUserId]
at org.hibernate.hql.internal.ast.QuerySyntaxException.generateQueryException(QuerySyntaxException.java:79) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.QueryException.wrapWithQueryString(QueryException.java:103) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:218) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:142) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:115) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:76) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:150) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:302) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:240) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1894) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at com.thp.clinic.tataInsurance.dao.InsuranceDaoImpl.userHashExists(InsuranceDaoImpl.java:24) ~[classes/:na]
at com.thp.clinic.tataInsurance.dao.InsuranceDaoImpl$$FastClassBySpringCGLIB$$f257a089.invoke(<generated>) [classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) [spring-core-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) [spring-tx-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at com.thp.clinic.tataInsurance.dao.InsuranceDaoImpl$$EnhancerBySpringCGLIB$$87c1fe8a.userHashExists(<generated>) [classes/:na]
at com.thp.clinic.tataInsurance.service.InsuranceServiceImpl.checkInsurance(InsuranceServiceImpl.java:32) [classes/:na]
at com.thp.clinic.tataInsurance.service.InsuranceServiceImpl$$FastClassBySpringCGLIB$$31bac4e9.invoke(<generated>) [classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) [spring-core-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) [spring-tx-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) [spring-tx-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) [spring-tx-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at com.thp.clinic.tataInsurance.service.InsuranceServiceImpl$$EnhancerBySpringCGLIB$$49b68a9f.checkInsurance(<generated>) [classes/:na]
at com.thp.clinic.tataInsurance.controller.InsuranceController.checkInsurance(InsuranceController.java:31) [classes/:na]
My application.properties is as follows:
server.port=8080
spring.jpa.database=POSTGRESQL
spring.datasource.platform=postgres
spring.database.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/INSURANCE_DB
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.show-sql=true
#spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.hibernate.ddl-auto = update
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
#auth protected here
endpoints.shutdown.sensitive=false
#Enable shutdown endpoint
endpoints.shutdown.enabled=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
My Application configuration class is as follows:
import org.hibernate.SessionFactory;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication()
#ComponentScan(basePackages = { "com.clinic.Insurance" })
public class Application {
#Bean
public SessionFactory sessionFactory(HibernateEntityManagerFactory hemf) {
return hemf.getSessionFactory();
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
The Dao is as follows:
#Override
public String userHashExists(Long consumerUserId) throws Exception{
Session session = null;
try {
session = factory.openSession();
Query query = session.createQuery("from HashMapping where consumerUserId=:consumerUserId");
query.setParameter("consumerUserId", consumerUserId);
HashMapping mapping = (HashMapping) query.uniqueResult();
if(mapping!=null)
return mapping.getConsumerHash();
return null;
} catch(Exception e){
logger.error("Exception in userHashExists Dao", e);
throw e;
} finally {
if(session!=null) {
session.close();
}
}
}
The Model/persistance class is as follows:
package com.clinic.Insurance.persistance;
import java.sql.Timestamp;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
#Entity
#Table(name = "hash_mapping")
public class HashMapping {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "auto_gen")
#SequenceGenerator(name = "auto_gen", sequenceName = "hash_mapping_hash_mapping_id_seq")
#Column(name = "hash_mapping_id")
private Long hashMappingId;
#Column(name = "consumer_user_id")
private Long consumerUserId;
#Column(name = "consumer_hash")
private String consumerHash;
#Column(name = "modified_timestamp")
#Temporal(TemporalType.TIMESTAMP)
private Timestamp modifiedTimestamp;
public Long getHashMappingId() {
return hashMappingId;
}
public void setHashMappingId(Long hashMappingId) {
this.hashMappingId = hashMappingId;
}
public Long getConsumerUserId() {
return consumerUserId;
}
public void setConsumerUserId(Long consumerUserId) {
this.consumerUserId = consumerUserId;
}
public String getConsumerHash() {
return consumerHash;
}
public void setConsumerHash(String consumerHash) {
this.consumerHash = consumerHash;
}
public Timestamp getModifiedTimestamp() {
return modifiedTimestamp;
}
public void setModifiedTimestamp(Timestamp modifiedTimestamp) {
this.modifiedTimestamp = modifiedTimestamp;
}
}
Can someone please help where I am going wrong.
DO I need to define something like <hibernate-mapping package="it.besmart.models"> as we do in spring servelet configuration. If yes how to do it in my existing code?
Answering where I was going wrong.
Add #EntityScan(basePackages = { "youentitypackage" }) along with #ComponentScan(basePackages = { "com.app" }). This will look for your entity classes.
I think this mistake "Query query = session.createQuery("from HashMapping where consumerUserId=:consumerUserId");"When make a request to the database,need add "SELECT" your entity in table WHERE....
OR "HashMapping" to "hash_mapping" (class entity must be same name as database)

Resources