What is the appropriate driver to load for embedded DynamoDB in a Spring app? - spring

I followed various tutorials to end up with the configuration below. There may also be incorrect configuration causing the problem. When I run the tests, I get:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.tomcat.jdbc.pool.DataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (the profiles "test" are currently active).
Research has lead me to believe that the appropriate driver is not being loaded and I have to add it to .properties. Is that something included in DynamoDBLocal library? I can't find it in the docs and it seems my only option is to get a 3rd party driver from the web.
Here's are the important parts:
pom.xml:
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-dynamodb</artifactId>
<version>1.11.34</version>
</dependency>
<dependency>
<groupId>com.github.derjust</groupId>
<artifactId>spring-data-dynamodb</artifactId>
<version>4.3.1</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>DynamoDBLocal</artifactId>
<version>1.10.5.1</version>
</dependency>
DataSourceConfigLocal:
#Configuration
#EnableWebMvc
#EnableDynamoDBRepositories(basePackages="com.cfa.dao")
#Profile({"local", "test"})
public class DataSourceConfigLocal {
#Value("${amazon.dynamodb.endpoint}")
private String amazonDynamoDBEndpoint;
#Value("${amazon.aws.accesskey}")
private String amazonAWSAccessKey;
#Value("${amazon.aws.secretkey}")
private String amazonAWSSecretKey;
#Bean
public AmazonDynamoDB amazonDynamoDB() {
AmazonDynamoDB amazonDynamoDB
= new AmazonDynamoDBClient(amazonAWSCredentials());
if (!StringUtils.isEmpty(amazonDynamoDBEndpoint)) {
amazonDynamoDB.setEndpoint(amazonDynamoDBEndpoint);
}
return amazonDynamoDB;
}
#Bean
public AWSCredentials amazonAWSCredentials() {
return new BasicAWSCredentials(
amazonAWSAccessKey, amazonAWSSecretKey);
}
}
IntegrationTest:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#Profile("test")
#TestPropertySource(properties = {
"amazon.dynamodb.endpoint=http://localhost:8000/",
"amazon.aws.accesskey=x",
"amazon.aws.secretkey=x" })
public class OrderRequestRepositoryIntegrationTest {
private DynamoDBMapper dynamoDBMapper;
#Autowired
private AmazonDynamoDB amazonDynamoDB;
#Autowired
OrderRequestDao orderRequestDao;
private static final String STORE_NUMBER = "100";
#Before
public void setup() throws Exception {
dynamoDBMapper = new DynamoDBMapper(amazonDynamoDB);
CreateTableRequest tableRequest = dynamoDBMapper
.generateCreateTableRequest(OrderRequest.class);
tableRequest.setProvisionedThroughput(
new ProvisionedThroughput(1L, 1L));
amazonDynamoDB.createTable(tableRequest);
dynamoDBMapper.batchDelete(
(List<OrderRequest>)orderRequestDao.findAll());
}
#Test
public void sampleTestCase() {
OrderRequest orderRequest = new OrderRequest(STORE_NUMBER);
orderRequestDao.save(orderRequest);
List<OrderRequest> result
= (List<OrderRequest>) orderRequestDao.findAll();
assertTrue("Not empty", result.size() > 0);
assertTrue("Contains item with expected cost",
result.get(0).getStoreNumber().equals(STORE_NUMBER));
}
}

I am not sure whether you have already referred this. I am adding this as it may help you.
Test using HTTP and without using HTTP
pom file which has the server runner and sql lite
1) Also, use the latest version 1.11.0.1 of the JAR.
2) SQL Lite lib in classpath
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>DynamoDBLocal</artifactId>
<version>${aws.dynamodblocal.version}</version>
</dependency>
<profile>
<id>start-dynamodb-local</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${exec.maven.plugin.version}</version>
<executions>
<execution>
<phase>initialize</phase>
<configuration>
<executable>java</executable>
<arguments>
<argument>-cp</argument>
<classpath/>
<argument>-Dsqlite4java.library.path=${basedir}/target/dependencies</argument>
<argument>com.amazonaws.services.dynamodbv2.local.main.ServerRunner</argument>
<argument>-inMemory</argument>
<argument>-port</argument>
<argument>${dynamodb-local.port}</argument>
</arguments>
</configuration>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>

Related

Springboot with both aspectj and Spring AOP

I am trying to get a springboot (2.6.2) project to work with both AspectJ and Spring AOP.
I have the following sample classes:
#Entity
public class Item {
#Id #Getter private String uuid = UUID.randomUUID().toString();
private String name;
#Verify.Access
public String getName() {
return name;
}
}
public #interface Verify {
#Target({ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#interface Access {}
}
#Aspect
#Slf4j
public class MyAspect {
#Before("#annotation(Verify.Access)")
public void beforeAnnotation(JoinPoint joinPoint) {
log.error("BEFORE ANNOTATION");
}
}
#Aspect
#Service
public class OtherAspect {
#Autowired private MyUtility myUtility;
#Around("#annotation(SystemCall)")
public Object run(#NonNull final ProceedingJoinPoint join) throws Throwable {
return myUtility.getInfo();
}
}
#Service
#Data
public class MyUtility {
Object info;
}
My pom.xml file has the following plugins defined:
<plugin>
<groupId>com.nickwongdev</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.12.6</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<proc>none</proc>
<complianceLevel>${java.version}</complianceLevel>
<showWeaveInfo>true</showWeaveInfo>
<forceAjcCompile>true</forceAjcCompile>
<sources/>
<weaveDirectories>
<weaveDirectory>${project.build.directory}/classes</weaveDirectory>
</weaveDirectories>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-maven-plugin</artifactId>
<version>1.18.20.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>delombok</goal>
</goals>
</execution>
</executions>
<configuration>
<addOutputDirectory>false</addOutputDirectory>
<sourceDirectory>src/main/java</sourceDirectory>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
I have also defined a src/main/resources/org/aspectj/aop.xml:
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<include within="mypackage..*" />
<include within="org.springframework.boot..*" />
</weaver>
<aspects>
<aspect name="mypackage.MyAspect" />
</aspects>
</aspectj>
It seems to compile okay and I see the info messages that the join points are being advised.
However, in the OtherAspect the autowired MyUtility is not getting set.
From what I could find I would expect Spring to recognize OtherAspect as a Component and Autowire in MyUtility but instead I get a NullPointerException.
Any thoughts?
Thanks!
OK, I had a little bit of time and prepared the MCVE which actually would have been your job to provide. I made the following assumptions:
You need native AspectJ, because you want to weave a target class which is not a Spring bean.
You want to use compile-time, not load-time weaaving. Therefore, you would use AspectJ Maven Plugin.
You want to use Spring dependency injection for wiring Spring beans into native AspectJ aspects, as described in the Spring manual, i.e. using an aspectOf factory method for the native aspect in Spring.
You absolutely insist on combining Lombok and native AspectJ, even though they are incompatible out of the box. I.e., you need a workaround in Maven, either binary weaving (e.g. if Lombok is only used for your non-aspect classes) or a "delombok" build step (e.g. if your aspects also use Lombok, which unfortunately they do, using the #Slf4j Lombok annotation in MyAspect.
What I changed in your setup:
I removed the dependency on Spring Data JPA to make things easier, because I was too lazy to set up a dummy in-memory database. It is not relevant for the solution here. I.e., I also commented out the #Entity and #Id annotations in class Item.
You already configured a "delombok" build step, which I wanted to stick with, because it seems to be your preference. Hence, your sample code only compiles with AspectJ Maven when using ${project.build.directory}/generated-sources/delombok as the source directory. Your idea to use a <weaveDirectory> does not work, because the aspect with the Lombok annotation does not compile that way, as it refers to the Lombok-generated static log field.
I removed the #Service annotation from the native AspectJ aspect, because that would lead to problems when wiring the application. Instead, I added a #Bean factory method to OtherAspect, so we can use #Autowired MyUtility myUtility there. In the same aspect, I also switched from #annotation(SystemCall) (due to missing code in your example) to #annotation(Verify.Access) in order to have something to test against.
I removed the superfluous aop.xml file.
I added a little Spring Boot driver application.
I switched from the no longer maintained com.nickwongdev AspectJ Maven plugin to the current dev.aspectj plugin which has more features and supports Java 17+, too.
The whole application looks like this:
<?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>
<groupId>org.example</groupId>
<artifactId>SO_AJ_SpringAutowireBeanNativeAspect_74661663</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<aspectj.version>1.9.9.1</aspectj.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>dev.aspectj</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.13.1</version>
<configuration>
<complianceLevel>${maven.compiler.target}</complianceLevel>
<proc>none</proc>
<showWeaveInfo>true</showWeaveInfo>
<forceAjcCompile>true</forceAjcCompile>
<sources>
<source>
<basedir>${project.build.directory}/generated-sources/delombok</basedir>
</source>
</sources>
<!--
<weaveDirectories>
<weaveDirectory>${project.build.directory}/classes</weaveDirectory>
</weaveDirectories>
-->
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-maven-plugin</artifactId>
<version>1.18.20.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>delombok</goal>
</goals>
</execution>
</executions>
<configuration>
<addOutputDirectory>false</addOutputDirectory>
<sourceDirectory>src/main/java</sourceDirectory>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.6.2</version>
<scope>compile</scope>
</dependency>
<!--
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.6.2</version>
<scope>compile</scope>
</dependency>
-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
</dependencies>
</project>
package org.example;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public #interface Verify {
#Target({ ElementType.METHOD })
#Retention(RetentionPolicy.RUNTIME)
#interface Access {}
}
package org.example;
import lombok.Data;
import org.springframework.stereotype.Service;
#Service
#Data
public class MyUtility {
Object info;
}
package org.example;
import lombok.Getter;
//import javax.persistence.Entity;
//import javax.persistence.Id;
import java.util.UUID;
//#Entity
public class Item {
// #Id
#Getter
private String uuid = UUID.randomUUID().toString();
private String name;
public Item(String name) {
this.name = name;
}
#Verify.Access
public String getName() {
return name;
}
}
package org.example;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
#Slf4j
public class MyAspect {
#Before("#annotation(Verify.Access)")
public void beforeAnnotation(JoinPoint joinPoint) {
log.error("BEFORE ANNOTATION");
}
}
package org.example;
import lombok.NonNull;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
#Aspect
public class OtherAspect {
#Autowired
private MyUtility myUtility;
// #Around("#annotation(SystemCall)")
#Around("#annotation(Verify.Access)")
public Object run(#NonNull final ProceedingJoinPoint join) throws Throwable {
return myUtility.getInfo();
// return join.proceed();
}
}
package org.example;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.Aspects;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#SpringBootApplication
#Configuration
#Slf4j
public class Main {
#Bean
public OtherAspect otherAspect() {
return Aspects.aspectOf(OtherAspect.class);
}
public static void main(String[] args) {
try (ConfigurableApplicationContext appContext = SpringApplication.run(Main.class, args)) {
doStuff(appContext);
}
}
private static void doStuff(ConfigurableApplicationContext appContext) {
MyUtility myUtility = appContext.getBean(MyUtility.class);
myUtility.setInfo("my info");
Item item = new Item("my name");
log.info(item.getName());
}
}
If you run the Spring Boot application, you will see the following on the console (timestamps removed):
ERROR 20680 --- [ main] org.example.MyAspect : BEFORE ANNOTATION
INFO 20680 --- [ main] org.example.Main : my info
As you can see, both aspects kick in, the first one logging an ERROR and the other one changing the return value from "my name" to "my info".
The advantage of the "delombok" variant is that within the same Maven module, you can weave aspects into the Lombok-generated source code. The disadvantage is, that in your IDE you might not be able to compile the project imported from Maven because of the very unusual custom configuration. In IntelliJ IDEA, I had to delegate the build to Maven, but still the source code editor shows squiggly lines.
As an alternative, you could create one module with Lombok compilation (no "delombok") and a second module using binary weaving in order to weave aspects into the Lombok-enhanced class files, as described here. It would all be much easier without Lombok, though. The third alternative is compilation with Lombok and native AspectJ load-time weaving configured for Spring Boot instead of compile-time or binary weaving during build time. I cannot explain and show every variant in detail here, it is a long answer already.

How Inyect dependency by interface mapper

I try to use mapstruct in java Spring to mapper object DTO to Object normal
I try to call the interface mapper since the service, but I have NullPointerException, seems the interface is not injected in service I used autowired and I quit this
Service
#Service
public class FollowService implements IFollowService{
#Autowired
IFollowRepository iFollowRepository;
private IUserMapper iUserMapper;
#Override
public UserDTOCount countFollowers(int userId) throws UserIdNotFoundException, UserNotFollowException {
return iUserMapper.toUserCount(iFollowRepository.getUserById(userId));
}
Mapper
#Mapper(componentModel = "spring")
public interface IUserMapper {
#Mappings({
#Mapping(source = "id" , target = "id"),
#Mapping(source = "name", target = "name"),
#Mapping(source = "followers", target = "followers", qualifiedByName = "followers")
})
UserDTOCount toUserCount(User user);
Error
processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException: null
at com.reto1.demo.Service.FollowService.countFollowers(FollowService.java:54) ~[classes/:na]
I try to debug and I see the iUserMapper is Null, I dont know How call since service
Thanks!
The reason why the iUserMapper is null in your FollowService is because you are not injecting your mapper.
You need to add #Autowired in your service.
e.g.
#Service
public class FollowService implements IFollowService{
#Autowired
IFollowRepository iFollowRepository;
#Autowired
private IUserMapper iUserMapper;
#Override
public UserDTOCount countFollowers(int userId) throws UserIdNotFoundException, UserNotFollowException {
return iUserMapper.toUserCount(iFollowRepository.getUserById(userId));
}
}
Small remark: One small digression note from me. I would suggest not prefixing the interfaces with I. The IDEs can clearly show what is a class and what is an interface and it is also easier to see them in your tree structure as not everything is under "I"
After see many questions, I resolve the error this form
-First, add plugin in pom.xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source> <!-- depending on your project -->
<target>1.8</target> <!-- depending on your project -->
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<!-- other annotation processors -->
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
Second I added lombok
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.4.1.Final</version>
</path>
And finally, I add autowired
#Service
public class FollowService implements IFollowService{
#Autowired
IFollowRepository iFollowRepository;
#Autowired
IUserMapper iUserMapper;

Not able to inject #Service and #Contract dependency in my resource class

On base of the guide from this blog, Roll your own Auto Discovery with Jersey and HK2, I have the follow resource POJO:
#Path("Test")
public class TestResource {
#Inject
private TestService service;
#GET
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Set<Test> getTests() {
return service.getAllTests();
}
}
The TestService:
#Contract
public interface TestService {
public Set<Test> getAllTests();
}
The TestServiceImpl
#Service
public class TestServiceImpl implements TestService {
#Override
public Set<Test> getAllTests() {
Set<Test> tests = new HashSet<>();
Test c = new Test();
c.setName("test");
tests.add(c);
return tests;
}
}
The Jersey dependency in pom.xml is of version 2.25.1
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<!-- use the following artifactId if you don't need servlet 2.x compatibility -->
<!-- artifactId>jersey-container-servlet</artifactId -->
</dependency>
<dependency>
<groupId>org.glassfish.jersey.bundles</groupId>
<artifactId>jaxrs-ri</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2</artifactId>
<version>2.5.0-b36</version>
</dependency>
In order to make Jersey scan the #Service and #Contract classes automatically, I used the inhabitant-generator plugin with version 2.5.0-b36:
<plugin>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2-inhabitant-generator</artifactId>
<version>2.5.0-b36</version>
<executions>
<execution>
<goals>
<goal>generate-inhabitants</goal>
</goals>
</execution>
</executions>
</plugin>
There is the corresponding Feature implementation:
public class AutoServiceDiscovery implements Feature {
#Override
public boolean configure(FeatureContext context) {
ServiceLocator locator = ServiceLocatorProvider.getServiceLocator(context);
DynamicConfigurationService dcs = locator.getService(DynamicConfigurationService.class);
Populator populator = dcs.getPopulator();
try {
populator.populate(new ClasspathDescriptorFileFinder(this.getClass().getClassLoader()),
new DuplicatePostProcessor());
} catch (IOException | MultiException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
}
return true;
}
}
And it is indeeded registered through my ResourceConfig class:
#ApplicationPath("/*")
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
packages("resources");
register(new AutoServiceDiscovery());
}
}
However, I send request to the /test, got the following error:
MultiException has 3 exceptions. They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for
injection at SystemInjecteeImpl(requiredType=TestService,parent=TestResource,qualifiers=
{},position=-1,optional=false,self=false,unqualified=null,1947073589)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of
rx.practice.ee.jaxrs.resources.TestResource errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on
rx.practice.ee.jaxrs.resources.TestResource
org.jvnet.hk2.internal.Collector.throwIfErrors(Collector.java:89)
org.jvnet.hk2.internal.ClazzCreator.resolveAllDependencies(ClazzCreator.java:250)
org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:358)
org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:487)
org.glassfish.jersey.process.internal.RequestScope.findOrCreate(RequestScope.java:162)
...
Question: Anyone knows why the #Service class cannot be injected? I am using Tomcat server
After a couple of days research on the source code of inhabitat-generator, I figured out that in case of web application package,war, the locator file is not generated in META-INF/hk2-locator as demonstracted in the HK2 Inhabitant Generator office site in case of using jar as deployment package. The source code of AbstractInhabitantsGeneratorMojo.java told that in case of war, locator files are generated in hk2-locator, and this is not mentioned in the HK2 Inhabitant Generator office site.
However, when constructing the ClasspathDescriptorFileFinder without the directory names argument in the bootstrap class, AutoServiceDiscovery, it is only compatible with jar as deployment package, meaning it is only finding files in META-INF/hk2-locator.
So the better solution would be not to use inhabitant-generator plugin but the metadata-generator dependency, which is an annotation processor at compile time and, it is proved out-of-the-box.
If someone is persistent to using this plugin, he/she could create his/her own ClasspathDescriptorFileFinder so that it is able to find locator files from hk2-locator
Last but not least, I also tried to use the inhabitants-generator plugin's options to generate the locator files in hk2-locator, but this seems to be next to impossible as well

How to return serialized object using MappingJackson2HttpMessageConverter

I am learning Spring Framework and the first goal for me is to return an Version object using a built in serializer.
public class Version {
private int build;
private String releaseType;
public Version(int build, String releaseType) {
this.build = build;
this.releaseType = releaseType;
}
public int getBuild() {
return build;
}
public String getReleaseType() {
return releaseType;
}
public void setBuild(int build) {
this.build = build;
}
public void setReleaseType(String releaseType) {
this.releaseType = releaseType;
}
}
And my root class (I called it Kernel), would love to stay with application configuration using one class
#EnableWebMvc
#Configuration
public class Kernel extends AbstractDispatcherServletInitializer implements WebMvcConfigurer {
#Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext annotationConfigWebApplicationContext = new AnnotationConfigWebApplicationContext();
annotationConfigWebApplicationContext.register(VersionController.class);
return annotationConfigWebApplicationContext;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/*" };
}
#Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter());
}
}
The controller
#RestController
public class VersionController {
#RequestMapping("/version")
#ResponseBody
public Version getVersion() {
return new Version(192837, "DEV");
}
}
I am trying to go as simple as I can, I don't have any XML file in my project as I want to go fully Annotation & Java mode as long as I can.
I never really liked the XML driven concept in Spring Framework as most of time the content of these XML files looks like exposed programmer garbage that nobody but owner would understand how to setup. What is the point of exposing configuration for response serializers as deployment worker will have no clue what is that.
The error I got is:
HTTP Status 500 – Internal Server Error, No converter found for return value of type
I suspect that the Jackson is not called because Spring does not know that he is expected to use it on Version object, but I have no idea how to force Spring to do it.
My pom.xml just for sure (using Tomcat9 as web server)
<?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>
<groupId>pl.protean.league-craft</groupId>
<artifactId>league-craft</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<warName>lc</warName>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>Kernel</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
I solved my issue thanks to this answer
https://stackoverflow.com/a/10650452/2010246
A
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter());
}
Will not work just like that even if I am overriding this method in AbstractDispatcherServletInitializer
Instead of that I had to create separate class for MVC configuration
package configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import java.util.List;
#Configuration
public class Mvc extends WebMvcConfigurationSupport {
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(converter());
addDefaultHttpMessageConverters(converters);
}
#Bean
MappingJackson2HttpMessageConverter converter() {
return new MappingJackson2HttpMessageConverter();
}
}
Now it loads correctly and I can simply return the class like I wanted to
I guess the core problem was there were no class that is annotated as #Configuration and extends the WebMvcConfigurationSupport parent

ClassNotFoundException CrudRepository

I'm reading the JPA docs on spring, and i'm trying to restructure my code.
What i have now:
BrewerRepository
#Repository
public class BrewerRepository {
#PersistenceContext(name = "vivesPU")
private EntityManager entityManager;
public List<Brewer> getAll() {
return null;
}
}
BrewerService
#Service
public class BrewerService {
#Autowired
private BrewerRepository brewerRepository;
public List<Brewer> getAll() {
return null;
}
}
HomeController
#Controller
public class HomeController {
#Autowired
private BrewerService brewerService;
#GetMapping("/")
public String index(Model model) {
List<Brewer> brewers = this.brewerService.getAll();
model.addAttribute("brewers", brewers);
return "index";
}
}
PersistenceJPAConfig
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories
public class PersistenceJPAConfig{
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setDataSource(dataSource());
entityManager.setPackagesToScan("org.vives.model");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
entityManager.setJpaVendorAdapter(vendorAdapter);
entityManager.setJpaProperties(additionalProperties());
return entityManager;
}
#Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.apache.derby.jdbc.EmbeddedDriver");
dataSource.setUrl("jdbc:derby://localhost:1527/beers;create=true");
dataSource.setUsername( "app" );
dataSource.setPassword( "app" );
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManager){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManager);
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
private Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.DerbyTenSevenDialect");
properties.setProperty("hibernate.transaction.jta.platform", "org.hibernate.service.jta.platform.internal.SunOneJtaPlatform");
properties.setProperty("hibernate.show_sql", "true");
return properties;
}
}
With this code, the application starts without problems.
When i change the Repository and Service like this:
#Repository
public interface BrewerRepository extends CrudRepository<Brewer, Long> {
}
#Service
public class BrewerService {
#PersistenceContext(name = "vivesPU")
private EntityManager entityManager;
#Autowired
private BrewerRepository brewerRepository;
public List<Brewer> getAll() {
return null;
}
}
Error log:
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'homeController': Unsatisfied dependency expressed through field 'brewerService'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'brewerService' defined in file [.\glassfish-5.0\glassfish5\glassfish\domains\domain1\applications\spring-mvc-quickstart-1.0-SNAPSHOT\WEB-INF\classes\org\vives\service\BrewerService.class]: Post-processing of merged bean definition failed; nested exception is java.lang.IllegalStateException: Failed to introspect Class [org.vives.service.BrewerService] from ClassLoader [WebappClassLoader (delegate=true; repositories=WEB-INF/classes/)]]]
...
Context initialization failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'homeController': Unsatisfied dependency expressed through field 'brewerService'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'brewerService' defined in file [.\glassfish-5.0\glassfish5\glassfish\domains\domain1\applications\spring-mvc-quickstart-1.0-SNAPSHOT\WEB-INF\classes\org\vives\service\BrewerService.class]: Post-processing of merged bean definition failed; nested exception is java.lang.IllegalStateException: Failed to introspect Class [org.vives.service.BrewerService] from ClassLoader [WebappClassLoader (delegate=true; repositories=WEB-INF/classes/)]
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'brewerService' defined in file [.\glassfish-5.0\glassfish5\glassfish\domains\domain1\applications\spring-mvc-quickstart-1.0-SNAPSHOT\WEB-INF\classes\org\vives\service\BrewerService.class]: Post-processing of merged bean definition failed; nested exception is java.lang.IllegalStateException: Failed to introspect Class [org.vives.service.BrewerService] from ClassLoader [WebappClassLoader (delegate=true; repositories=WEB-INF/classes/)]
...
Caused by: java.lang.IllegalStateException: Failed to introspect Class [org.vives.service.BrewerService] from ClassLoader [WebappClassLoader (delegate=true; repositories=WEB-INF/classes/)]
...
Caused by: java.lang.NoClassDefFoundError: org/springframework/data/repository/CrudRepository
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at org.glassfish.web.loader.WebappClassLoader.findClass(WebappClassLoader.java:1059)
at org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1588)
at org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1471)
at java.lang.Class.getDeclaredFields0(Native Method)
at java.lang.Class.privateGetDeclaredFields(Class.java:2583)
at java.lang.Class.getDeclaredFields(Class.java:1916)
at org.springframework.util.ReflectionUtils.getDeclaredFields(ReflectionUtils.java:754)
... 82 more
Caused by: java.lang.ClassNotFoundException: org.springframework.data.repository.CrudRepository
at org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1621)
at org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1471)
... 92 more
]]
I've tried to look for an answer, but without success. Can someone explain to me why this is happening and tell me how I can fix it?
What I've tried so far:
checked the dependencies
deleted the .m2 folder and installed all
dependencies again messed a bit with annotations
changed a bit the project structure, according to this post
EDIT:
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>
<groupId>org.vives</groupId>
<artifactId>spring-mvc-quickstart</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>spring-mvc-quickstart</name>
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java-version>1.8</java-version>
<!-- Override Spring version -->
<spring.version>5.0.0.RELEASE</spring.version>
<jackson.version>2.9.1</jackson.version>
<thymeleaf-extras-java8time-version>3.0.1.RELEASE</thymeleaf-extras-java8time-version>
<!-- AssertJ is not a part of Spring IO platform, so the version must be provided explicitly -->
<assertj-core-version>3.8.0</assertj-core-version>
</properties>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.1.RELEASE</version>
</dependency>
<!-- Security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<!-- Avoid issue #72 Could not initialize class org.thymeleaf.templateresolver.ServletContextTemplateResolver due to 'validation is not supported' -->
<exclusions>
<exclusion>
<artifactId>pull-parser</artifactId>
<groupId>pull-parser</groupId>
</exclusion>
</exclusions>
<version>5.2.9.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-release</id>
<name>Spring Release Repository</name>
<url>https://repo.spring.io/release</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${endorsed.dir}</outputDirectory>
<silent>true</silent>
<artifactItems>
<artifactItem>
<groupId>javax</groupId>
<artifactId>javaee-endorsed-api</artifactId>
<version>7.0</version>
<type>jar</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Came to this error [ Caused by: java.lang.ClassNotFoundException: org.springframework.data.repository.CrudRepository ] was using springboot dev tools auto build
but stopped the program -> clean -> run solved the issue on my end.
the CrudRepository class is not found which means that the pom dependencies are not defined well. The Crud repository is defined the spring-data-jpa and it is included but i think the problem could be found in the spring different dependencies that you are using that may conflict with each other. for example some dependencies may be included as a child dependencies in others, so they must not be included again. Also you must make sure that the spring dependencies versions are consistent.
I cleared the .m2 repository (path e.g. C:\Users\Hetal Rachh\.m2\repository) and then did a mvn clean install build and it worked.
The Constructor Injection is missing like:
#Autowired
public BrewerService(BrewerRepository brewerRepository) {
this.brewerRepository = brewerRepository
}
#Override
public List<Brewer> getAll() {
return brewerRepository.findAll();
}
As Amr Alaa mentioned, there was an issue with the dependencies. I solved my problem by creating a new project in a different folder and adding the dependencies again.
I usually update the project and let it rebuild, then restart the program in the spring boot dashboard.

Resources