I'm trying to create a Unit Test for a RestController in Spring Boot.
The Controller looks something like this:
#RestController()
#RequestMapping("/endpoint")
public class MyRestController {
#Autowired
private MyService service;
#GetMapping(value = "/{id}", produces = "application/json")
public ResponseEntity<String> findSomethingById(#PathVariable("id") String id, #RequestParam("param1")String param1) throws MyServiceException {
return ResponseEntity.ok(service.findSomethingById(id,param1));
}
And the Unit Test Class looks as follows:
import org.junit.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.isA;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
#ExtendWith(SpringExtension.class)
#WebMvcTest(MyRestController.class)
public class MyRestControllerUnitTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private MyService service;
#Test
public void testGetSomethingId() throws Exception {
when(service.findSomethingById("1", "something")).thenReturn("found");
mockMvc.perform(get("/endpoint/1").param("param1","something"))
.andDo(print())
.andExpect(status().isOk());
// some more Expects
}
}
The issue is that both the service and the mockMvc Variables are null during the execution of the Test, but shouldn't be as they should get intantiated by Spring according to their Annotations according to my Understanding.
Looking for similair issues I found mostly issues where Junit4 and Junit5 got mixed togehter, which seems not to be my problem.
Sample question I found NullPointerException on controller when testing in SpringBoot API - Mocking
I'm using Spring Boot 2.7.4 as well as Java 11 and I added the spring-boot-starter-test dependency to my pom.xml for the Test dependencies
Below is the StackTrace I get when executing the Test with my IDEA:
java.lang.NullPointerException
at MyRestControllerUnitTest.findSomethingById(Line of when() as service is null and so is mockMvc)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:42)
at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:80)
at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:72)
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:86)
at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Process finished with exit code -1
MainClass:
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.myGroup</groupId>
<artifactId>myArtifact</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>MyApplication</name>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2020.0.3</spring-cloud.version>
<start-class>org.main.MyApplication</start-class>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</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-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.12</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>org.main.MyApplication</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
The issue is coming because of the #Test annotation. You are using this annotation from the org.junit.Test package that is part of Junit4. Other annotations used in the test case are part of Junit5. So this is conflicting. Please use #Test annotation from the org.junit.jupiter.api.Test package and try again.
Also, remove this dependency from the pom.xml
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
Adding to the answer by Rohit Agarwal, if you run
./mvw dependency:tree
You shall see transitive dependencies added by the spring-boot-test
\- org.springframework.boot:spring-boot-starter-test:jar:2.7.5:test
[INFO] +- org.springframework.boot:spring-boot-test:jar:2.7.5:test
[INFO] +- org.springframework.boot:spring-boot-test autoconfigure:jar:2.7.5:test
[INFO] +- com.jayway.jsonpath:json-path:jar:2.7.0:test
[INFO] | \- net.minidev:json-smart:jar:2.4.8:test
[INFO] | \- net.minidev:accessors-smart:jar:2.4.8:test
[INFO] | \- org.ow2.asm:asm:jar:9.1:test
[INFO] +- jakarta.xml.bind:jakarta.xml.bind-api:jar:2.3.3:test
[INFO] | \- jakarta.activation:jakarta.activation-api:jar:1.2.2:test
[INFO] +- org.assertj:assertj-core:jar:3.22.0:test
[INFO] +- org.hamcrest:hamcrest:jar:2.2:test
[INFO] +- org.junit.jupiter:junit-jupiter:jar:5.8.2:test <------------- Note this
[INFO] | +- org.junit.jupiter:junit-jupiter-api:jar:5.8.2:test
JUnit 5 added by spring-boot-test as a transitive dependency as shown above.
Since Springboot 2.4 Junit4 Vintage engine is removed.
Hence you should use the Junit5 Test annotation org.junit.jupiter.api.Test
Related
EDIT/UPDATE: Delegate IDE build/run actions to maven in IntelliJ settings solve the problem, but how to handle it without it?
I have the following problem:
I change something in my GetSthAspect class -> Then I run maven clean install (let's assume I have to always do clean install in my app) -> Run spring app -> And I see error:
java.lang.NoSuchMethodError: com.example.demo.aspects.GetSthAspect.aspectOf()Lcom/example/demo/aspects/GetSthAspect;
at com.example.demo.aspects.A.shouldDoSthAndCallMethodGetSth(A.java:15) ~[classes/:na]
at com.example.demo.aspects.AspectApp.main(AspectApp.java:18) ~[classes/: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.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.10.jar:5.3.10]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.10.jar:5.3.10]
...
Then I stop app -> Again do maven clean install -> Again run app and now everything works fine.
It's always like that when I change something in my GetSthAspect class and I want to see my changes in app. Why is that? Why I have to build app -> run app -> stop app -> again build app and run it in order to my aspects works fine? What should I do to avoid this situation?
GetSthAspect
#Aspect
public class GetSthAspect {
Logger logger = LoggerFactory.getLogger(GetSthAspect.class);
#Around("call(* Ent.getSth())")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
logger.info("Inside around + 12:52");
Ent ent = (Ent) pjp.getTarget();
logger.info("Number: " + ent.getImportantNumber());
return pjp.proceed();
}
}
some class
public class AspectApp {
Logger logger = LoggerFactory.getLogger(AspectApp.class);
#GetMapping("/")
public String main() {
logger.info("Method main started + 11:01");
A a = new A();
a.shouldDoSthAndCallMethodGetSth(1);
}
}
A
public class A {
Logger logger = LoggerFactory.getLogger(A.class);
public void shouldDoSthAndCallMethodGetSth(Integer a) {
// ...
Ent ent = new Ent();
ent.setImportantNumber(1);
logger.info("Method A do sth and ...");
ent.getSth();
}
}
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Testing</name>
<description>App for tests</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.7</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.14.0</version>
<configuration>
<complianceLevel>11</complianceLevel>
<source>11</source>
<target>11</target>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<Xlint>ignore</Xlint>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<goals>
<!-- use this goal to weave all your main classes -->
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
I can't tell where the problem is. normally you don't need to keep to maven clean install everytime you change something in your code.I suggest you use devtools maybe
atlas-package runs without errors. But I got errors with Quick Reload.
Error is:
JiraRendererPlugin.class] cannot be opened because it does not exist
I imported this interface in java code. No errors while compilation still.
I changed dependency for jira-core in pom.xml. From "provided" to "runtime" => I got out of memory error while compilation. Added memory to maven - doesn't help.
Errors
[INFO] [talledLocalContainer] 2020-06-02 20:17:15,258 QuickReload - Plugin Installer INFO [c.a.plugin.loaders.ScanningPluginLoader] Removed plugin 'com.vladmak.ringcentral.jira-cmp-plgin'
[INFO] [talledLocalContainer] 2020-06-02 20:17:15,314 QuickReload - Plugin Installer INFO [c.a.plugin.util.WaitUntil] Plugins that have yet to be enabled: (1): [com.vladmak.ringcentral.jira-cmp-plgin], 300 seconds remaining
[INFO] [talledLocalContainer] 2020-06-02 20:17:15,337 ThreadPoolAsyncTaskExecutor::Thread 52 ERROR [c.a.p.osgi.factory.OsgiPlugin] Unable to start the plugin container for plugin 'com.vladmak.ringcentral.jira-cmp-plgin'
[INFO] [talledLocalContainer] org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.vladmak.ringcentral.jiracmp.CMRRenderer]; nested exception is java.io.FileNotFoundException: class path resource [com/atlassian/jira/issue/fields/renderer/JiraRendererPlugin.class] cannot be opened because it does not exist
[INFO] [talledLocalContainer] at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:182)
[INFO] [talledLocalContainer] at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:321)
[INFO] [talledLocalContainer] at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanFactory(ConfigurationClassPostProcessor.java:261)
[INFO] [talledLocalContainer] at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.invokeBeanFactoryPostProcessors(AbstractDelegatedExecutionApplicationContext.java:444)
[INFO] [talledLocalContainer] at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.invokeBeanFactoryPostProcessors(AbstractDelegatedExecutionApplicationContext.java:414)
[INFO] [talledLocalContainer] at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.invokeBeanFactoryPostProcessors(AbstractDelegatedExecutionApplicationContext.java:362)
[INFO] [talledLocalContainer] at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext$3.run(AbstractDelegatedExecutionApplicationContext.java:254)
[INFO] [talledLocalContainer] at org.eclipse.gemini.blueprint.util.internal.PrivilegedUtils.executeWithCustomTCCL(PrivilegedUtils.java:85)
[INFO] [talledLocalContainer] at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.startRefresh(AbstractDelegatedExecutionApplicationContext.java:220)
[INFO] [talledLocalContainer] at org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor.stageOne(DependencyWaiterApplicationContextExecutor.java:224)
[INFO] [talledLocalContainer] at org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor.refresh(DependencyWaiterApplicationContextExecutor.java:177)
[INFO] [talledLocalContainer] at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.refresh(AbstractDelegatedExecutionApplicationContext.java:157)
[INFO] [talledLocalContainer] at org.eclipse.gemini.blueprint.extender.internal.activator.LifecycleManager$1.run(LifecycleManager.java:207)
[INFO] [talledLocalContainer] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[INFO] [talledLocalContainer] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[INFO] [talledLocalContainer] at java.lang.Thread.run(Thread.java:748)
[INFO] [talledLocalContainer] Caused by: java.io.FileNotFoundException: class path resource [com/atlassian/jira/issue/fields/renderer/JiraRendererPlugin.class] cannot be opened because it does not exist
[INFO] [talledLocalContainer] at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:172)
[INFO] [talledLocalContainer] at org.springframework.core.type.classreading.SimpleMetadataReader.<init>(SimpleMetadataReader.java:50)
Class
package com.vladmak.ringcentral.jiracmp;
import com.atlassian.jira.issue.fields.renderer.wiki.AtlassianWikiRenderer;
import com.atlassian.event.api.EventPublisher;
//import com.atlassian.jira.issue.fields.renderer.IssueRenderContext;
//import com.atlassian.jira.plugin.renderer.JiraRendererModuleDescriptor;
import com.atlassian.jira.util.velocity.VelocityRequestContextFactory;
import com.atlassian.jira.config.properties.ApplicationProperties;
import com.atlassian.jira.config.FeatureManager;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.atlassian.plugin.spring.scanner.annotation.imports.JiraImport;
import com.atlassian.jira.issue.fields.renderer.JiraRendererPlugin;
//import com.atlassian.plugin.spring.scanner.annotation.export.ExportAsService;
//import com.atlassian.jira.issue.fields.renderer.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Component
public class CMRRenderer extends AtlassianWikiRenderer implements InitializingBean, DisposableBean {
private static final Logger log = LoggerFactory.getLogger(CMRRenderer.class);
public static final String TYPE = "cmr-renderer";
#JiraImport
private final EventPublisher eventPublisher;
#Autowired
public CMRRenderer(#JiraImport EventPublisher eventPublisher_f,
ApplicationProperties applicationProperties,
VelocityRequestContextFactory velocityRequestContextFactory,
FeatureManager featureManager) {
super(eventPublisher_f, applicationProperties, velocityRequestContextFactory, featureManager);
this.eventPublisher = eventPublisher_f;
}
/**
* Called when the plugin has been enabled.
*
* #throws Exception
*/
#Override
public void afterPropertiesSet() throws Exception {
log.info("[CMP] Enabling plugin");
eventPublisher.register(this);
}
/**
* Called when the plugin is being disabled or removed.
*
* #throws Exception
*/
#Override
public void destroy() throws Exception {
log.info("[CMP] Disabling plugin");
eventPublisher.unregister(this);
}
public String getRendererType() {
return TYPE;
}
}
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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.vladmak.ringcentral</groupId>
<artifactId>jira-cmp-plgin</artifactId>
<version>1.0-SNAPSHOT</version>
<organization>
<name>VLADmak</name>
<url>https://www.linkedin.com/in/vladmak/</url>
</organization>
<name>JIRA CMP Plugin</name>
<description>Add panel with CMRs details</description>
<packaging>atlassian-plugin</packaging>
<dependencies>
<dependency>
<groupId>com.atlassian.jira</groupId>
<artifactId>jira-api</artifactId>
<version>${jira.version}</version>
<scope>provided</scope>
</dependency>
<!-- Add dependency on jira-core if you want access to JIRA implementation classes as well as the sanctioned API. -->
<!-- This is not normally recommended, but may be required eg when migrating a plugin originally developed against JIRA 4.x -->
<dependency>
<groupId>com.atlassian.jira</groupId>
<artifactId>jira-core</artifactId>
<version>${jira.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-annotation</artifactId>
<version>${atlassian.spring.scanner.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-runtime</artifactId>
<version>${atlassian.spring.scanner.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
<scope>provided</scope>
</dependency>
<!-- WIRED TEST RUNNER DEPENDENCIES -->
<dependency>
<groupId>com.atlassian.plugins</groupId>
<artifactId>atlassian-plugins-osgi-testrunner</artifactId>
<version>${plugin.testrunner.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.2-atlassian-1</version>
</dependency>
<!-- Uncomment to use TestKit in your project. Details at https://bitbucket.org/atlassian/jira-testkit -->
<!-- You can read more about TestKit at https://developer.atlassian.com/display/JIRADEV/Plugin+Tutorial+-+Smarter+integration+testing+with+TestKit -->
<!--
<dependency>
<groupId>com.atlassian.jira.tests</groupId>
<artifactId>jira-testkit-client</artifactId>
<version>${testkit.version}</version>
<scope>test</scope>
</dependency>
-->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.8.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.atlassian.renderer</groupId>
<artifactId>atlassian-renderer</artifactId>
<version>8.0.9</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>jira-maven-plugin</artifactId>
<version>${amps.version}</version>
<extensions>true</extensions>
<configuration>
<productVersion>${jira.version}</productVersion>
<productDataVersion>${jira.version}</productDataVersion>
<!-- Uncomment to install TestKit backdoor in JIRA. -->
<!--
<pluginArtifacts>
<pluginArtifact>
<groupId>com.atlassian.jira.tests</groupId>
<artifactId>jira-testkit-plugin</artifactId>
<version>${testkit.version}</version>
</pluginArtifact>
</pluginArtifacts>
-->
<enableQuickReload>true</enableQuickReload>
<!-- See here for an explanation of default instructions: -->
<!-- https://developer.atlassian.com/docs/advanced-topics/configuration-of-instructions-in-atlassian-plugins -->
<instructions>
<Atlassian-Plugin-Key>${atlassian.plugin.key}</Atlassian-Plugin-Key>
<!-- Add package to export here -->
<Export-Package>com.example.plugins.tutorial.api,</Export-Package>
<!-- Add package import here -->
<Import-Package>org.springframework.osgi.*;resolution:="optional", org.eclipse.gemini.blueprint.*;resolution:="optional", *</Import-Package>
<!-- Ensure plugin is spring powered -->
<Spring-Context>*</Spring-Context>
</instructions>
</configuration>
</plugin>
<plugin>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-maven-plugin</artifactId>
<version>${atlassian.spring.scanner.version}</version>
<executions>
<execution>
<goals>
<goal>atlassian-spring-scanner</goal>
</goals>
<phase>process-classes</phase>
</execution>
</executions>
<configuration>
<scannedDependencies>
<dependency>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-external-jar</artifactId>
</dependency>
</scannedDependencies>
<verbose>false</verbose>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<jira.version>7.13.0</jira.version>
<amps.version>8.0.2</amps.version>
<plugin.testrunner.version>2.0.1</plugin.testrunner.version>
<atlassian.spring.scanner.version>1.2.13</atlassian.spring.scanner.version>
<!-- This property ensures consistency between the key in atlassian-plugin.xml and the OSGi bundle's key. -->
<atlassian.plugin.key>${project.groupId}.${project.artifactId}</atlassian.plugin.key>
<!-- TestKit version 6.x for JIRA 6.x -->
<testkit.version>6.3.11</testkit.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>
This class JiraRendererPlugin is part of
<dependency>
<groupId>com.atlassian.jira</groupId>
<artifactId>jira-api</artifactId>
<version>${jira.version}</version>
<scope>provided</scope>
</dependency>
You are using the correct scope and everything else seems legit.
I suggest to erase your local copy jira-api, v7.13.0
C:\Applications\Atlassian\atlassian-plugin-sdk-8.0.16\repository\com\atlassian\jira\jira-api\7.13.0
After erasing, re run atlas-run or atlas-debug
I am not sure if this would fix it. Just a wild guess.
Although my index.jsp opens in a browser with a Status 200 it only displays the JSP code.
I've read through what seem to be all related issues/solutions on this site, but none of the solutions have worked. e.g. adding jstl, jasper, etc. jars into my pom.xml and build path; mapping variations like "/", "/*", etc. No errors in the Spring log- just that JSPs aren't rendering or being "seen" as JSPs. My newest theories are that something is over-writing or conflicting, or that Spring needs something to "see" JSPs under the WEB-INF folder, but it's not easy to debug. Seems a stupid thing that a JSP doesn't render, so any insight would be helpful.
AppConfig
package mil.dfas.springmvc.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
/**
* #author David Higgins
*/
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"mil.dfas.springmvc.controller"})
public class AppConfig {
#Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setViewClass(JstlView.class);
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
}
LMSInitializer
package mil.dfas.springmvc.config;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import mil.dfas.filters.LoginFilter;
import mil.dfas.filters.TimeoutFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
* The Spring MVC DispatcherServlet needs to be declared and mapped for all request processing.
* In a Servlet 3.0+ environment, AbstractAnnotationConfigDispatcherServletInitializer class is used to register and initialize the DispatcherServlet programmatically.
*
* #author $Author: David Higgins $
* #version $Revision: 1.0 $ $Date: 2019/05/12 $
*/
public class LMSInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
private static final Logger LOGGER = LoggerFactory.getLogger(LMSInitializer.class);
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
FilterRegistration timeoutFilter = servletContext.addFilter("timeoutFilter", new TimeoutFilter());
timeoutFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "*.do");
super.onStartup(servletContext);
}
#Override
protected Filter[] getServletFilters() {
LOGGER.info("LMSInitializer: Configuring Servlet Filters" );
LoginFilter loginFilter = new LoginFilter();
return new Filter[] {new LoginFilter()};
}
#Override
protected Class <?> [] getRootConfigClasses() {
return null;
}
#Override
protected Class <?> [] getServletConfigClasses() {
return new Class[] {AppConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
}
LMSController
package mil.dfas.springmvc.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
/**
* #author David Higgins
*/
#Controller
public class LMSSpringController {
#RequestMapping(value = "/index", method = RequestMethod.POST)
public ModelAndView forward(Model model) {
System.out.println("LMS Controller");
model.addAttribute("msg","Forward Handled");
return new ModelAndView("index");
}
}
WEB-INF/views/index.jsp
No error messages. JSPs just don't displays as JSPs.
The problem must be something with the pom.xml. It must be a conflict with dependencies. I've added jasper, jstl, and others, but no change. Status 200 and no log errors, but no jsp rendering.
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version> <!-- 2.1.5.RELEASE ? -->
<relativePath />
</parent>
<groupId>mil.dfas.springmvc</groupId>
<artifactId>EmployeeDevelopment</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<failOnMissingWebXml>false</failOnMissingWebXml>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- Spring-boot-starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!-- I think maybe including servlet dependencies is forcing servlet version
to 4.0 since no versions are included, so Spring Boot parent will provide
the defaults and maybe force latest version (?) A lot of this servlet stuff
should already be included in Tomcat bin (on build path) -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<!-- <scope>provided</scope> -->
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>com.keypoint</groupId>
<artifactId>png-encoder</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<version>1.8.2</version>
</dependency>
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.jfree</groupId>
<artifactId>jfreechart</artifactId>
<version>1.0.14</version>
</dependency>
<dependency>
<groupId>jfree</groupId>
<artifactId>jcommon</artifactId>
<version>1.0.16</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>xalan</groupId>
<artifactId>xalan</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.7</version>
</dependency>
<!-- As Oracle JDBC drivers are not in public Maven repositories (legal
reasons) downloading the jar was the best available option. -->
<dependency>
<groupId>com.oracle.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>12.2.0.1</version>
<scope>system</scope>
<systemPath>${basedir}/src/lib/ojdbc8.jar</systemPath>
</dependency>
<!-- Added 5/17/19 DJM, may want to get directly from Maven repo -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mailapi</artifactId>
<version>1.4.3</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<plugins>
<plugin>
<!-- <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source>
<target>1.8</target> </configuration> -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Package as an executable jar/war -->
</plugins>
</build>
</project>
I try to add mapstruct mapper in my Spring project.
I have a User entity. I need to show a list of users in the admin panel. For this, I did DTO UserForAdmin, mapper UserMapper and rest controller AdminRestController. When I try to get UserMapper I get errors.
I try two ways:
Mappers.getMapper(UserMapper.class)
I get error
java.lang.ClassNotFoundException: Cannot find implementation for
ru.project.mapper.UserMapper
Autowired
I get error
Error starting ApplicationContext. To display the conditions report
re-run your application with 'debug' enabled. 2019-07-17 15:47:07.886
ERROR 13652 --- [ restartedMain]
o.s.b.d.LoggingFailureAnalysisReporter :
*************************** APPLICATION FAILED TO START
Description:
Field userMapper in ru.project.controller.rest.AdminRestController
required a bean of type 'ru.project.mapper.UserMapper' that could not
be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'ru.project.mapper.UserMapper' in
your configuration.
Here my source code.
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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>ru.project</groupId>
<artifactId>project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>project</name>
<description>The project is project of resourse for investors.</description>
<properties>
<java.version>12</java.version>
<org.mapstruct.version>1.3.0.Final</org.mapstruct.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.3.5</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
My interface UserMapper:
package ru.project.mapper;
import java.util.List;
import org.mapstruct.Mapper;
import ru.project.domain.User;
import ru.project.dto.UserForAdmin;
#Mapper
//#Mapper(componentModel = "spring")
public interface UserMapper {
UserForAdmin UserToUserForAdmin(User user);
List<UserForAdmin> UserListToUserForAdminList(List<User> user);
}
My RestController:
package ru.project.controller.rest;
import java.util.List;
import org.mapstruct.factory.Mappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import ru.project.dto.UserForAdmin;
import ru.project.mapper.UserMapper;
import ru.project.service.UserService;
#RestController
public class AdminRestController {
#Autowired
private UserService userService;
//#Autowired
//private UserMapper userMapper;
#GetMapping("/admin/users")
public List<UserForAdmin> findAllUsers(){
UserMapper userMapper = Mappers.getMapper(UserMapper.class);
return userMapper.UserListToUserForAdminList(userService.findAll());
}
}
I would like to use Awtowired.
You need to use #Mapper(componentModel="spring")
package ru.project.mapper;
import java.util.List;
import org.mapstruct.Mapper;
import ru.project.domain.User;
import ru.project.dto.UserForAdmin;
#Mapper(componentModel = "spring")
public interface UserMapper {
UserForAdmin UserToUserForAdmin(User user);
List<UserForAdmin> UserListToUserForAdminList(List<User> user);
}
and use below in AdminRestController
#Autowired
private UserMapper userMapper;
And i am assuming that User and UserForAdmin have same field names
After this run mvn clean compile and sources will be generated
An alternative answer to using annotation #Mapper(componentModel = "spring") would be to add the component model as compiler arguments in the plugin. The annotation works but the annoying thing may be having to add it to every mapper you create. A compiler argument you add once and works for all mappers in the project. Below is an example of a plugin definition with the componentModel compiler argument.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${org.projectlombok.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-Amapstruct.defaultComponentModel=spring</arg>
</compilerArgs>
</configuration>
</plugin>
I have tried this with versions 1.3.0.Final as well as 1.3.1.Final and sping boot 2.1.7/8/9
Use #Mapper(componentModel = "spring") - enable di.
Run mvn package command -it creates the implementation class.
#Autowired the mapper interface and use.
(method name start letter in java should be lower case)
There is one simple solution.
at your mapper class, use #Mapper(componentModel = "spring")
and the run mvn clean install command from terminal.
or in case of STS/ Eclipse, go to Project> Run As> maven clean
and then run Project> Run As> maven install
and your mapper Impl will be generated!
NOTE: Regarding to plugins
if you're using both of following dependencies then no need to use plugin in pom.xml file
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
and properties will be like;
<properties>
<java.version>11</java.version>
<org.mapstruct.version>1.3.1.Final</org.mapstruct.version>
</properties>
I solved it by adding scanBasePackages
#SpringBootApplication(scanBasePackages = {
"com.yourpackagepath.mapper"
})
Cannot find implementation for ru.project.mapper.UserMapper that means UserMapper must be implements by some class.
such as public Class UserMapperImple implements UserMapper {XXXXXXX}
then the Mappers.getMapper("UserMapper") will get UserMapperImple.
Consider defining a bean of type 'ru.project.mapper.UserMapper' in your configuration. that means #Mapper do not work; i advise you to check the spring-config.xml. may the ApplicationContext not scan this package.
hope to help you :)
I have built a very simple bundle which has zero dependencies and imports no packages. Its only content is a CalculatorService interface and corresponding implementation class containing just a simple add(int a, int b) method.
I have created two PaxExam test containers for this bundle, one using a Karaf container, and the other an OSGI container. The Karaf container tests work fine, but the OSGI test container does not.
To clarify a bit... if I remove the injection of the CalculatorService into the OSGI test container, and directly instantiate the CalculatorServiceImpl class in my JUnit test case, it works fine. So the class from my simple bundle is visible to the OSGI test container.
Some questions:
Is there something I am missing in my pom.xml files to make this work?
Should I add more bundles to my OsgiTestClient.config() method?
Other ideas on what is keeping is very stripped down example from working?
The following is the stack trace I get when trying to inject the CalculatorService into my PaxExam OSGI test container.
org.ops4j.pax.swissbox.tracker.ServiceLookupException: gave up waiting for service info.xyz.common.Calculator
at org.ops4j.pax.swissbox.tracker.ServiceLookup.getService(ServiceLookup.java:199)
at org.ops4j.pax.swissbox.tracker.ServiceLookup.getService(ServiceLookup.java:136)
at org.ops4j.pax.exam.inject.internal.ServiceInjector.injectField(ServiceInjector.java:89)
at org.ops4j.pax.exam.inject.internal.ServiceInjector.injectDeclaredFields(ServiceInjector.java:69)
at org.ops4j.pax.exam.inject.internal.ServiceInjector.injectFields(ServiceInjector.java:61)
at org.ops4j.pax.exam.invoker.junit.internal.ContainerTestRunner.createTest(ContainerTestRunner.java:61)
at org.junit.runners.BlockJUnit4ClassRunner$1.runReflectiveCall(BlockJUnit4ClassRunner.java:266)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.ops4j.pax.exam.invoker.junit.internal.ContainerTestRunner.runChild(ContainerTestRunner.java:68)
at org.ops4j.pax.exam.invoker.junit.internal.ContainerTestRunner.runChild(ContainerTestRunner.java:37)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.ops4j.pax.exam.invoker.junit.internal.JUnitProbeInvoker.invokeViaJUnit(JUnitProbeInvoker.java:124)
at org.ops4j.pax.exam.invoker.junit.internal.JUnitProbeInvoker.findAndInvoke(JUnitProbeInvoker.java:97)
at org.ops4j.pax.exam.invoker.junit.internal.JUnitProbeInvoker.call(JUnitProbeInvoker.java:73)
at org.ops4j.pax.exam.nat.internal.NativeTestContainer.call(NativeTestContainer.java:112)
at org.ops4j.pax.exam.spi.reactors.AllConfinedStagedReactor.invoke(AllConfinedStagedReactor.java:84)
at org.ops4j.pax.exam.junit.impl.ProbeRunner$2.evaluate(ProbeRunner.java:267)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.ops4j.pax.exam.junit.impl.ProbeRunner.run(ProbeRunner.java:98)
at org.ops4j.pax.exam.junit.PaxExam.run(PaxExam.java:93)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
The pom.xml for my simple bundle containing the Calculator service is as follows:
<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>info.xyz</groupId>
<artifactId>xyz-businessLogic</artifactId>
<version>0.0.1</version>
<packaging>bundle</packaging>
<dependencies>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Bundle-Version>${project.version}</Bundle-Version>
<Import-Package>
</Import-Package>
<Export-Package>
info.xyz.common,
info.xyz.common.impl
</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
It is clear there are zero dependencies to my simple bundle, and the packages containing the Calculator and CalculatorImpl files are exported. Below is the blueprint.xml file for defining these services.
<?xml version="1.0" encoding="UTF-8"?>
<blueprint default-activation="eager" xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://aries.apache.org/xmlns/jpa/v1.0.0" xmlns:tx="http://aries.apache.org/xmlns/transactions/v1.0.0"
xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0
http://www.w3.org/2001/XMLSchema-instance http://www.w3.org/2001/XMLSchema-instance
http://aries.apache.org/xmlns/jpa/v1.0.0 http://aries.apache.org/xmlns/jpa/v1.0.0
http://aries.apache.org/xmlns/transactions/v1.0.0 http://aries.apache.org/xmlns/transactions/v1.0.0">
<bean id="calculatorService" class="info.xyz.common.impl.CalculatorImpl" />
<service ref="calculatorService" interface="info.xyz.common.Calculator" />
</blueprint>
Next, the pom.xml for my PaxExam OSGI container is as follows:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>info.xyz</groupId>
<artifactId>xyz-test-osgi</artifactId>
<version>0.0.1</version>
<parent>
<groupId>info.xyz</groupId>
<artifactId>xyz</artifactId>
<version>0.0.1</version>
<relativePath>../xyz</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-container-native</artifactId>
<version>${pax.exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-junit4</artifactId>
<version>${pax.exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-link-mvn</artifactId>
<version>${pax.exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.url</groupId>
<artifactId>pax-url-aether</artifactId>
<version>${pax.url.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam</artifactId>
<version>${pax.exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-inject</artifactId>
<version>${pax.exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.framework</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${ch.qos.logback.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${ch.qos.logback.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>${javax.inject.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- Testing target -->
<dependency>
<groupId>info.xyz</groupId>
<artifactId>xyz-businessLogic</artifactId>
<version>0.0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Needed if you use versionAsInProject() -->
<plugin>
<groupId>org.apache.servicemix.tooling</groupId>
<artifactId>depends-maven-plugin</artifactId>
<version>1.3.1</version>
<executions>
<execution>
<id>generate-depends-file</id>
<goals>
<goal>generate-depends-file</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Finally, the OSGI Test class is given as follows:
package info.xyz.test.osgi;
import static org.ops4j.pax.exam.CoreOptions.junitBundles;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import info.xyz.common.Calculator;
import javax.inject.Inject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.ProbeBuilder;
import org.ops4j.pax.exam.TestProbeBuilder;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerMethod;
import org.osgi.framework.Constants;
#RunWith(PaxExam.class)
#ExamReactorStrategy(PerMethod.class)
public class OsgiTestClient
{
#Inject
protected Calculator _calculator;
#ProbeBuilder
public TestProbeBuilder probeConfiguration(TestProbeBuilder probe)
{
System.out.println("TestProbeBuilder gets called");
probe.setHeader(Constants.DYNAMICIMPORT_PACKAGE, "*");
probe.setHeader(Constants.IMPORT_PACKAGE, "info.xyz.common");
probe.setHeader(Constants.IMPORT_PACKAGE, "info.xyz.common.impl");
return probe;
}
#Configuration
public Option[] config()
{
return new Option[] {
junitBundles(),
mavenBundle().groupId("info.xyz").artifactId("xyz-businessLogic").versionAsInProject(),
};
}
#Test
public void testAdd()
{
info.xyz.common.impl.CalculatorImpl calculator = new info.xyz.common.impl.CalculatorImpl();
int result = calculator.add(1, 2);
System.out.println("--- testing: ");
}
}
One final comment, if I comment out the code for injecting the CalculatorService, the code runs fine (as I am manually instantiating the CalculatorImpl class). So my test container does have both compile-time and run-time visibility to the Calculator interface and implementation. But injection of this service is not working.
And a final reminder, when I build a PaxExam Karaf Test Container, the injection of the Calculator service is successful and the test cases run fine. The error is when running the PaxExam OSGI container described in this post.
Yes, then it is that the blueprint stack/libraries are not installed by default in native container (but they are in Karaf).
You need to add this deps to your test pom:
<dependency>
<groupId>org.apache.aries</groupId>
<artifactId>org.apache.aries.util</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.aries.proxy</groupId>
<artifactId>org.apache.aries.proxy.api</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.aries.proxy</groupId>
<artifactId>org.apache.aries.proxy.impl</artifactId>
<version>1.0.4</version>
</dependency>
<dependency>
<groupId>org.apache.aries.blueprint</groupId>
<artifactId>org.apache.aries.blueprint.api</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.aries.blueprint</groupId>
<artifactId>org.apache.aries.blueprint.core</artifactId>
<version>1.4.2</version>
</dependency>
<dependency>
<groupId>org.apache.aries.blueprint</groupId>
<artifactId>org.apache.aries.blueprint.core.compatibility</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.aries.blueprint</groupId>
<artifactId>org.apache.aries.blueprint.cm</artifactId>
<version>1.0.5</version>
</dependency>
And add the following bundles to your configuration in your test:
mavenBundle().groupId("org.apache.aries").artifactId("org.apache.aries.util").versionAsInProject(),
mavenBundle().groupId("org.apache.aries.proxy").artifactId("org.apache.aries.proxy.api").versionAsInProject(),
mavenBundle().groupId("org.apache.aries.proxy").artifactId("org.apache.aries.proxy.impl").versionAsInProject(),
mavenBundle().groupId("org.apache.aries.blueprint").artifactId("org.apache.aries.blueprint.api").versionAsInProject(),
mavenBundle().groupId("org.apache.aries.blueprint").artifactId("org.apache.aries.blueprint.cm").versionAsInProject(),
mavenBundle().groupId("org.apache.aries.blueprint").artifactId("org.apache.aries.blueprint.core").versionAsInProject(),
mavenBundle().groupId("org.apache.aries.blueprint").artifactId("org.apache.aries.blueprint.core.compatibility").versionAsInProject().noStart(),
That should make the trick!