Deprecated methods when using Feign with Oauth2 in SpringBoot 2.4.3 - spring-boot

I am trying to use feign client with Oauth2 in my project based in Springboot 2.4.3. I implemented this example but the DefaultOAuth2ClientContext, OAuth2ProtectedResourceDetails and ClientCredentialsResourceDetails methods are deprecated.
pom.xml
<dependencies>
....
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
....
</dependencies>
application.yml
config:
serverUrl : exampleUrl
clientId: exampleClientId
clientSecret: exampleClientSecret
scopes: exampleScopes
feign:
post:
name: postService
url: https://localhost:8102/post
get:
name: getService
url: https://localhost:8102/get
FeignClient.java
#FeignClient(name = "example", configuration = OAuth2ClientConfig.class)
public interface FeignClient {
#PostMapping(value = "${feign.post.url}")
HttpEntity search(#PathVariable String id);
#GetMapping(value = "${feign.get.url}")
HttpEntity upload(#PathVariable String id);
}
OAuth2ClientProperties.java
#ConfigurationProperties(prefix = "config")
public class OAuth2ClientProperties {
private String serverUrl;
private String clientId;
private String clientSecret;
private List<String> scopes = new ArrayList<>();
public String getAccessTokenUri() {
return serverUrl;
}
public void setAccessTokenUri(String accessTokenUri) {
this.serverUrl = accessTokenUri;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getClientSecret() {
return clientSecret;
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
public List<String> getScopes() {
return scopes;
}
public void setScopes(List<String> scopes) {
this.scopes = scopes;
}
}
OAuth2ClientConfig.java
import feign.RequestInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.security.oauth2.client.feign.OAuth2FeignRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
#Configuration
#EnableConfigurationProperties(OAuth2ClientProperties.class)
public class OAuth2ClientConfig {
#Autowired
private OAuth2ClientProperties oAuth2ClientProperties;
#Bean
public RequestInterceptor requestInterceptor() {
return new OAuth2FeignRequestInterceptor(new DefaultOAuth2ClientContext(),
oAuth2ProtectedResourceDetails());
}
private OAuth2ProtectedResourceDetails oAuth2ProtectedResourceDetails() {
ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails();
details.setClientId(oAuth2ClientProperties.getClientId());
details.setClientSecret(oAuth2ClientProperties.getClientSecret());
details.setAccessTokenUri(oAuth2ClientProperties.getAccessTokenUri());
details.setScope(oAuth2ClientProperties.getScopes());
return details;
}
}
I have not yet tested whether it works or not, but what bothers me is having deprecated methods and I have not found a solution to replace them with equivalents taken into account by the new version.
Any ideas ?

Related

#RefreshScope not working with external config files

I added the following dependencies in my pom so I could make use of Spring cloud
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Added spring-cloud.version as Finchley.RELEASE
This is the bean that I intend to refresh:
#Component
#ConfigurationProperties(ignoreUnknownFields = true,prefix="global")
#PropertySource(value = "${spring.config.location}")
#Getter
#Setter
#Validated
#RefreshScope
public class GeneralProperties {
private String mode;
}
Accessing the bean in my controller:
#RestController
#RequestMapping
#RefreshScope
public class AppController {
private static final AnalyticsLogger LOGGER = AnalyticsLoggerFactory
.getLogger(AppController.class);
#Autowired
SimulatorRequestProcessor simulatorRequestProcessor;
#Autowired
GeneralProperties generalProperties;
#ResponseBody
#PostMapping(value = "/api/mock-getdata", produces = "application/json")
public String fetchResponseBasedOnMode(#RequestHeader HttpHeaders headers,
#RequestBody String request) {
String response = null;
LOGGER.info("color: "+color);
switch (generalProperties.getMode()) {
//code
Properties set in application config:
spring.config.location=file:///var/lib/data/demo/config/generalConfig.properties
management.endpoints.web.exposure.include=refresh
Unable to refresh the value of mode. Can someone point out the error in this code. My property files are in a folder that is not committed in git, so I am not making use of spring-cloud-config.
Put this in src/main/resources/application.properties
management.endpoints.web.exposure.include=*
Run this program with this argument --spring.config.additional-location=/tmp/application.properties
package com.example.demorefreshscopeexternalfile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.core.style.ToStringCreator;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#SpringBootApplication
#RestController
#EnableConfigurationProperties(DemorefreshscopeexternalfileApplication.MyProps.class)
public class DemorefreshscopeexternalfileApplication {
#Autowired
MyProps props;
#RequestMapping
public String message() {
return props.getMessage();
}
public static void main(String[] args) {
SpringApplication.run(DemorefreshscopeexternalfileApplication.class, args);
}
#ConfigurationProperties("my")
public static class MyProps {
private String message;
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
#Override
public String toString() {
return new ToStringCreator(this)
.append("message", message)
.toString();
}
}
}
contents of /tmp/application.properties
my.message=message from /tmp
view http://localhost:8080
/tmp/application.properties can be updated, the post to /actuator/refresh and view 8080 again and you will see updated values.
Built with boot 2.2.4 and Hoxton.SR1
See https://docs.spring.io/spring-boot/docs/2.2.4.RELEASE/reference/html/appendix-application-properties.html#common-application-properties for spring.config.* and their meaning.

ElasticSearch credentials in Spring boot

I'm trying to integrate Spring boot elasticsearch with a standalone ES remote server, so I've installed ES locally and it works fine.
My problem now when enable xpack.security.enabled: true in elasticsearch.yml file (For production purposes), I don't know how to add username & password properly.
I've tried multiple ways but useless.
my pom.xml file
<dependencies>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.1.2</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>6.1.2</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client-sniffer</artifactId>
<version>6.1.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
my application.properties file
spring.data.elasticsearch.cluster-name=elasticsearch
spring.data.elasticsearch.cluster-nodes=localhost:9300
it's working fine if the ES server doesn't require any authentication
Asuming you are creating your elasticSearchOperation soemthing like this:
public ElasticsearchOperations elasticsearchTemplate(final JestClient jestClient,
final ElasticsearchConverter elasticsearchConverter,
final SimpleElasticsearchMappingContext simpleElasticsearchMappingContext,
EntityMapper mapper) {
return new JestElasticsearchTemplate(
jestClient,
elasticsearchConverter,
new DefaultJestResultsMapper(simpleElasticsearchMappingContext, mapper));
}
you need to configure the credentials in the JestClient which you can do like this :
JestHttpClient build() {
JestClientFactory factory = new JestClientFactory();
Builder builder =
new HttpClientConfig.Builder(cfg.urls)
.multiThreaded(true)
.discoveryEnabled(false)
.connTimeout((int) cfg.connectionTimeout)
.maxConnectionIdleTime(cfg.maxConnectionIdleTime, cfg.maxConnectionIdleUnit)
.maxTotalConnection(cfg.maxTotalConnection)
.readTimeout(cfg.readTimeout)
.requestCompressionEnabled(cfg.requestCompression)
.discoveryFrequency(1L, TimeUnit.MINUTES);
if (cfg.username != null && cfg.password != null) {
builder.defaultCredentials(cfg.username, cfg.password);
}
factory.setHttpClientConfig(builder.build());
return (JestHttpClient) factory.getObject();
}
Note that since your server is remote you want to create the HttpClientConfig..
EDITS : Try something like this.... havent tested myself, meaning is not working/tested code but you can get an idea
package com.asimplemodule.config;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.github.vanroy.springdata.jest.JestElasticsearchTemplate;
import com.github.vanroy.springdata.jest.mapper.DefaultJestResultsMapper;
import io.searchbox.client.JestClient;
import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.EntityMapper;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import java.io.IOException;
#Configuration
#EnableConfigurationProperties(ElasticsearchProperties.class)
public class ElasticsearchConfiguration {
private ObjectMapper mapper;
public ElasticsearchConfiguration(ObjectMapper mapper) {
this.mapper = mapper;
}
#Bean
public EntityMapper getEntityMapper() {
return new CustomEntityMapper(mapper);
}
#Bean
#Primary
public ElasticsearchOperations elasticsearchTemplate( final ElasticsearchConverter elasticsearchConverter,
final SimpleElasticsearchMappingContext simpleElasticsearchMappingContext,
EntityMapper mapper) {
final JestClient jestClient = createJestClient();
return new JestElasticsearchTemplate(
jestClient,
elasticsearchConverter,
new DefaultJestResultsMapper(simpleElasticsearchMappingContext, mapper));
}
public class CustomEntityMapper implements EntityMapper {
private ObjectMapper objectMapper;
public CustomEntityMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
objectMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, true);
objectMapper.configure(SerializationFeature.INDENT_OUTPUT, false);
objectMapper.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, true);
}
#Override
public String mapToString(Object object) throws IOException {
return objectMapper.writeValueAsString(object);
}
#Override
public <T> T mapToObject(String source, Class<T> clazz) throws IOException {
return objectMapper.readValue(source, clazz);
}
}
#Bean
public JestClient createJestClient(){
JestHttpClient build() {
JestClientFactory factory = new JestClientFactory();
Builder builder =
new HttpClientConfig.Builder(cfg.urls)
.multiThreaded(true)
.discoveryEnabled(false)
.connTimeout((int) cfg.connectionTimeout)
.maxConnectionIdleTime(cfg.maxConnectionIdleTime, cfg.maxConnectionIdleUnit)
.maxTotalConnection(cfg.maxTotalConnection)
.readTimeout(cfg.readTimeout)
.requestCompressionEnabled(cfg.requestCompression)
.discoveryFrequency(1L, TimeUnit.MINUTES);
if (cfg.username != null && cfg.password != null) {
builder.defaultCredentials(cfg.username, cfg.password);
}
factory.setHttpClientConfig(builder.build());
return (JestHttpClient) factory.getObject();
}
}
}
Try to add this configuration bean, so that it uses the JestClient with your credentials. you have to put your own values for where my cfg.whatever is

Spring Data 3.0.5 MongoDB and ElasticSearch Domain Class mixed Annotation

I'm migrating our application from Spring Boot 1.5.9 to version 2.0.0.
In version 1.5.9 we have successfully used mixed Annotations on several Domain Classes e.g:
...
#org.springframework.data.mongodb.core.mapping.Document(collection = "folder")
#org.springframework.data.elasticsearch.annotations.Document(indexName = "folder")
public class Folder {
...
}
The same approach causes probems in Spring Boot 2.0.0. When MongoDB annotatnion #DBRef is used, Spring throws exception while ElasticsearchRepository creation:
java.lang.IllegalStateException: No association found!
Here comes classes and confs
pom.xml
...
<properties>
<java.version>1.8</java.version>
</properties>
<parent>
<groupId>org.springfrsamework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
...
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>provided</scope>
</dependency>
</dependencies>
...
Application.java
...
#EnableMongoRepositories("com.hydra.sbmr.repoMongo")
#EnableElasticsearchRepositories("com.hydra.sbmr.repoElastic")
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Folder.java (Note this #DBRef couses exception)
package com.hydra.sbmr.model;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.DBRef;
#org.springframework.data.mongodb.core.mapping.Document(collection = "folder")
#org.springframework.data.elasticsearch.annotations.Document(indexName = "folder")
public class Folder {
#Id
#Getter #Setter private String id;
// Why MongoDB core mapping #DBRef causes java.lang.IllegalStateException: No association found! exception
// while ElasticsearchRepository creation???
#DBRef
#Getter #Setter private Profile profile;
#Getter #Setter private String something;
}
Profile.java
package com.hydra.sbmr.model;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
#org.springframework.data.mongodb.core.mapping.Document(collection = "profile")
public class Profile {
#Id
#Getter #Setter private String id;
#Getter #Setter String blah;
}
FolderElasticRepository.java
package com.hydra.sbmr.repoElastic;
import com.hydra.sbmr.model.Folder;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface FolderElasticRepository extends ElasticsearchRepository<Folder, String> {
}
You can find whole mini project on GitHub: https://github.com/hydraesb/sbmr
My question:
Is there any solution that will work with mixed Annotatnions on Domain Classes (mongo and elastic) in Spring Boot 2.0.0???
I have the same issue and the solution that i found is to extends SimpleElasticsearchMappingContext like this :
package com.mypackage;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.elasticsearch.client.Client;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.EntityMapper;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.io.IOException;
#Configuration
public class ElasticsearchConfiguration {
#Bean
public ElasticsearchTemplate elasticsearchTemplate(Client client, Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder) {
return new ElasticsearchTemplate(client, new MappingElasticsearchConverter(new CustomElasticsearchMappingContext()),
new CustomEntityMapper(jackson2ObjectMapperBuilder.createXmlMapper(false).build()));
}
public class CustomEntityMapper implements EntityMapper {
private ObjectMapper objectMapper;
public CustomEntityMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
}
#Override
public String mapToString(Object object) throws IOException {
return objectMapper.writeValueAsString(object);
}
#Override
public T mapToObject(String source, Class clazz) throws IOException {
return objectMapper.readValue(source, clazz);
}
}
}
package com.mypackage;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchPersistentEntity;
import org.springframework.data.mapping.model.Property;
import org.springframework.data.mapping.model.SimpleTypeHolder;
public class CustomElasticsearchMappingContext extends SimpleElasticsearchMappingContext {
#Override
protected ElasticsearchPersistentProperty createPersistentProperty(Property property, SimpleElasticsearchPersistentEntity owner, SimpleTypeHolder simpleTypeHolder) {
return new CustomElasticsearchPersistentProperty(property, owner, simpleTypeHolder);
}
}
package com.mypackage;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchPersistentProperty;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.model.Property;
import org.springframework.data.mapping.model.SimpleTypeHolder;
public class CustomElasticsearchPersistentProperty extends SimpleElasticsearchPersistentProperty {
public CustomElasticsearchPersistentProperty(Property property, PersistentEntity owner, SimpleTypeHolder simpleTypeHolder) {
super(property, owner, simpleTypeHolder);
}
#Override
public boolean isAssociation() {
return false;
}
}
I have faced this problem also and I fixed with solution of #ybouraze
#Bean
fun elasticsearchTemplate(client: JestClient, converter: ElasticsearchConverter, builder: Jackson2ObjectMapperBuilder): ElasticsearchOperations {
val entityMapper = CustomEntityMapper(builder.createXmlMapper(false).build())
val mapper = DefaultJestResultsMapper(converter.mappingContext, entityMapper)
return JestElasticsearchTemplate(client, converter, mapper)
}
#Bean
#Primary
fun mappingContext(): SimpleElasticsearchMappingContext {
return MappingContext()
}
#Bean
fun elasticsearchConverter(): ElasticsearchConverter {
return MappingElasticsearchConverter(mappingContext())
}
inner class CustomEntityMapper(private val objectMapper: ObjectMapper) : EntityMapper {
init {
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true)
}
#Throws(IOException::class)
override fun mapToString(`object`: Any): String {
return objectMapper.writeValueAsString(`object`)
}
#Throws(IOException::class)
override fun <T> mapToObject(source: String, clazz: Class<T>): T {
return objectMapper.readValue(source, clazz)
}
}
inner class MappingContext : SimpleElasticsearchMappingContext() {
override fun createPersistentProperty(property: Property, owner: SimpleElasticsearchPersistentEntity<*>, simpleTypeHolder: SimpleTypeHolder): ElasticsearchPersistentProperty {
return PersistentProperty(property, owner, simpleTypeHolder)
}
}
inner class PersistentProperty(property: Property, owner: SimpleElasticsearchPersistentEntity<*>, simpleTypeHolder: SimpleTypeHolder) : SimpleElasticsearchPersistentProperty(property, owner, simpleTypeHolder) {
override fun isAssociation(): Boolean {
return false
}
}

Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: No converter found for return value of type:

I am trying to expose REST service, but while hitting it from POSTMAN i am getting below :
WARNING: Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: No converter found for return value of type: class java.util.ArrayList
Where as i have also included below jar files which are required :
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.1</version>
</dependency>
Here is my REST controller Code :
#RestController
#RequestMapping("/MayankAPI")
public class TestRestAPI {
#RequestMapping(value="/sayHello" , method = RequestMethod.POST)
public TestPojo postData(#RequestBody String payload) {
System.out.println("Hello post"+payload);
TestPojo payload1=new TestPojo();
payload1.setStudentName("Jack");
return payload1;
}
#RequestMapping(value="/sayHello" , method = RequestMethod.GET)
public List<TestPojo> getData(String payload) {
System.out.println("Hello get"+payload);
List<TestPojo> payload1=new ArrayList<TestPojo>();
TestPojo tp = new TestPojo();
tp.setStudentName("Jack");
payload1.add(tp);
return payload1;
}
Here is my bean which i am trying to return :
public class TestPojo {
private String studentName;
private String studentId;
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public String getStudentId() {
return studentId;
}
public void setStudentId(String studentId) {
this.studentId = studentId;
}
}
Please help me where i am doing wrong.
I know it too late but still
Alternate Solution:
you need to enable Spring project as Web MVC as follow:
#Configuration
#EnableWebMvc
#ComponentScan("basePackages = com.test")
public class MiBenefitConfiguration
{
}
This is happening because MappingJackson2HttpMessageConverter is not registered in my App config file as below.
#Configuration
#ComponentScan("basePackages = com.test")
public class MiBenefitConfiguration extends WebMvcConfigurationSupport{
#Bean
public ObjectMapper getObjectMapper() {
return new ObjectMapper();
}
#Bean
public MappingJackson2HttpMessageConverter messageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(getObjectMapper());
return converter;
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(messageConverter());
addDefaultHttpMessageConverters(converters);
}
}

Spring Boot JPA repository error

i am try using spring boot with hibernate-mysql for learning
i follow the spring boot youtube tutorial and make some change for jpa hibernate-mysql
When run as "spring boot app", it was working fine.
When run as "maven package" on pom.xml, it was failed on "TESTS"
error:
2015-09-18 10:26:19.599 INFO 8328 --- [ main] demo.DemoApplicationTests : Starting DemoApplicationTests on Noir with PID 8328 (D:\eclipse\project\demo\target\test-classes started by Phane in D:\eclipse\project\demo)
2015-09-18 10:26:19.667 INFO 8328 --- [ main] o.s.w.c.s.GenericWebApplicationContext : Refreshing org.springframework.web.context.support.GenericWebApplicationContext#1d0737c8: startup date [Fri Sep 18 10:26:19 SGT 2015]; root of context hierarchy
2015-09-18 10:26:19.768 WARN 8328 --- [ main] o.s.w.c.s.GenericWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: file [D:\eclipse\project\demo\target\classes\filmRental\JpaConfig.class]; nested exception is java.lang.annotation.AnnotationFormatError: Invalid default: public abstract java.lang.Class org.springframework.data.jpa.repository.config.EnableJpaRepositories.repositoryBaseClass()
at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(ClassPathScanningCandidateComponentProvider.java:303)
at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:248)
at org.springframework.context.annotation.ComponentScanAnnotationParser.parse(ComponentScanAnnotationParser.java:140)
at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:266)
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:230)
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:189)
at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:270)
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:230)
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:197)
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:166)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:306)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:239)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:254)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:94)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:606)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:462)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
this is the java classes:
DemoApplication.java
package demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
import filmRental.Staff;
import filmRental.StaffRepository;
import filmRental.StaffServiceImpl;
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
#ComponentScan ("filmRental")
#Component
class StaffCommandLineRunner implements CommandLineRunner
{
#Override
public void run(String... arg0) throws Exception
{
for(Staff staff : this.sf.findAll())
{
System.out.println(staff.getStaffID() + " > " + staff.getFirstName());
}
}
#Autowired StaffServiceImpl sf;
}
StaffRestController
package demo;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import filmRental.Staff;
import filmRental.StaffServiceImpl;
#RestController
#ComponentScan ("filmRental")
public class StaffRestController
{
#RequestMapping ("/staff")
public Collection<Staff> listStaff()
{
return sf.findAll();
}
#Autowired StaffServiceImpl sf;
}
StaffServiceImpl.java
package filmRental;
import java.util.List;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
#Service
#Transactional
public class StaffServiceImpl
{
// #PersistenceContext
// private EntityManager em;
#Resource
private StaffRepository sf;
public List<Staff> findAll()
{
return sf.findAll();
}
}
StaffRepository.java
package filmRental;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.transaction.annotation.Transactional;
#Transactional
public interface StaffRepository extends JpaRepository<Staff, Byte>{}
Staff.java
package filmRental;
import java.sql.Blob;
import java.sql.Timestamp;
import javax.persistence.*;
#Entity
#Table (name ="Staff")
public class Staff
{
private byte staffID;
private String firstName;
private String lastName;
private byte[] picture;
private String email;
private byte storeID;
private boolean active;
private String userName;
private String password;
private Timestamp lastUpdate;
private Address address;
#Id
#Column (name="staff_id")
public byte getStaffID()
{
return staffID;
}
public void setStaffID(byte staffID)
{
this.staffID = staffID;
}
#Column (name = "first_name")
public String getFirstName()
{
return firstName;
}
public void setFirstName(String firstName)
{
this.firstName = firstName;
}
#Column (name = "last_name")
public String getLastName()
{
return lastName;
}
public void setLastName(String lastName)
{
this.lastName = lastName;
}
#Column (name = "picture", columnDefinition="BLOB")
public byte[] getPicture()
{
return picture;
}
public void setPicture(byte[] picture)
{
this.picture = picture;
}
#Column (name = "email")
public String getEmail()
{
return email;
}
public void setEmail(String email)
{
this.email = email;
}
#Column (name = "store_id")
public byte getStoreID()
{
return storeID;
}
public void setStoreID(byte storeID)
{
this.storeID = storeID;
}
#Column (name = "active")
public boolean getActive()
{
return active;
}
public void setActive(boolean active)
{
this.active = active;
}
#Column (name = "username")
public String getUserName()
{
return userName;
}
public void setUserName(String userName)
{
this.userName = userName;
}
#Column (name = "password")
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
#Column (name = "last_update")
public Timestamp getLastUpdate()
{
return lastUpdate;
}
public void setLastUpdate(Timestamp lastUpdate)
{
this.lastUpdate = lastUpdate;
}
#ManyToOne
#JoinColumn(name="address_id")
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
JpaConfig.java
package filmRental;
import java.util.Properties;
import javax.annotation.Resource;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.hibernate.ejb.HibernatePersistence;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#EnableTransactionManagement
#PropertySource("classpath:application.properties")
#EnableJpaRepositories
public class JpaConfig
{
private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
#Resource
private Environment env;
#Bean
public DataSource dataSource()
{
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory()
{
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistence.class);
entityManagerFactoryBean.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
entityManagerFactoryBean.setJpaProperties(hibProperties());
return entityManagerFactoryBean;
}
private Properties hibProperties()
{
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
return properties;
}
#Bean
public JpaTransactionManager transactionManager()
{
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>`enter code here`
<groupId>org.test</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-ws</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.9.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Please help, thanks.
You are using Spring Boot then use Spring Boot also the #ComponentScan should go on your application class. (remove it from your command line runner and controller).
#SpringBootApplication
#ComponentScan ({"demo","filmRental"})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
#Component
class StaffCommandLineRunner implements CommandLineRunner {
#Autowired StaffServiceImpl sf;
#Override
public void run(String... arg0) throws Exception {
for(Staff staff : this.sf.findAll()) {
System.out.println(staff.getStaffID() + " > " + staff.getFirstName());
}
}
}
Next in your pom remove the spring-data-jpa, hibernate and persistence-api dependencies and replace with spring-boot-starter-data-jpa
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-ws</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
Now you have dependencies that work together instead of trying to figure out a working combination.
Spring Boot already does auto configuration for you remove your JpaConfig and put the following properties in your application.properties (automatically loaded by Spring Boot!).
spring.datasource.url=<datasource-url>
spring.datasource.driver-class-name=<driver-class-name>
spring.datasource.username=<username>
spring.datasource.password=<password>
spring.jpa.database-platform=<hibernate-dialect>
spring.jpa.show-sql=<show-sql>
For the entity scan use #EntityScan on the application class.
#SpringBootApplication
#ComponentScan ({"demo","filmRental"})
#EntityScan("filmRental")
public class DemoApplication { ... }
Spring Boot now auto configures the DataSource, EntityManagerFactory, transactions, detects Spring Data JPA and enables repositories. I would suggest moving the DemoApplication and everything else in the filmRental package that way you can remove the #ComponentScan and #EntityScan from the DemoApplication.

Resources