Unable to run generated jar from spring-boot jersey - spring-boot

Im unable to run the generated jar file with my spring-boot with jersey project.
exception that i encounter is:
Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration': Unsatisfied dependency expressed through constructor parameter 1
Project runs properly when it's done via IDE (running the Main class) or when using spring-boot:run
Here are the details of the current setup:
Packaging:
jar
dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
<version>1.5.1.RELEASE</version>
</dependency>
my jersey configuration (ResourceConfig) is set to scan packages
#Component
public class JerseyConfiguration extends ResourceConfig {
public JerseyConfiguration() {
packages(true, "com.my.base.jaxrs.packages");
}
}
spring-boot-maven-plugin configured as:
org.springframework.boot
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
I also did not use the spring-boot-starter-parent but added the spring-boot-dependencies as indicated in the docs.

This is more of a workaround than an actual valid solution to use
packages(true, "my.package");
in reference to Anton's answer, i settled with this solution with the limitation that it requires resources with class level #Path or #Provider annotation:
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AnnotationTypeFilter(Path.class));
provider.addIncludeFilter(new AnnotationTypeFilter(Provider.class));
provider.findCandidateComponents("my.package.here").forEach(beanDefinition -> {
try {
LOGGER.info("registering {} to jersey config", beanDefinition.getBeanClassName());
register(Class.forName(beanDefinition.getBeanClassName()));
} catch (ClassNotFoundException e) {
LOGGER.warn("Failed to register: {}", beanDefinition.getBeanClassName());
}
});

I had this problem, I did not want to complicate things too much so I just registered all my jersey controllers individually.
#Configuration
public class JerseyConfig extends ResourceConfig {
JerseyConfig() {
// my old version that does not play well with spring boot fat jar
/*
packages(
"com.mycompany.api.resources"
);
*/
register(com.mycompany.api.resources.FooController.class);
register(com.mycompany.api.resources.BarController.class);
}
NOTE: I would not recommend this for large projects with many files, it will very quickly become long and unreadable and tedious to maintain.
That said, it is a working solution and you will be able to run your jar with the usual java -jar my-project.jar command.

Alternatively you could do,
#Configuration
public class JerseyConfig extends ResourceConfig {
JerseyConfig() {
BeanConfig beanConfig = new BeanConfig();
beanConfig.setResourcePackage("com.mycompany.api.resources");
}
}

Related

How to test OSGi declarative services using JUnit and tycho-surefire-plugin?

Tried to test an OSGi service using JUnit and the tycho-surefire-plugin.
Configuration of the plugin
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-surefire-plugin</artifactId>
<version>${tycho.version}</version>
<configuration>
<showEclipseLog>true</showEclipseLog>
<dependencies>
<dependency>
<type>p2-installable-unit</type>
<artifactId>org.eclipse.equinox.ds</artifactId>
</dependency>
</dependencies>
</configuration>
</plugin>
Testcase (logging statements etc. omitted). The test class is contained in it's own OSGi bundle, separated from the code under test.
#Component(name = "LdapConnectionConfigurationServiceTest", immediate = true)
public class LdapConnectionConfigurationServiceTest {
private LdapConnectionConfiguration testObject;
#Reference
public void bindTestObject(final LdapConnectionConfiguration testObject) {
this.testObject = testObject;
}
public void unbindTestObject(final LdapConnectionConfiguration testObject) {
this.testObject = null;
}
#Test
public void testLdapPort() {
assertEquals(10389, testObject.getLdapPort());
}
}
Tycho starts an OSGi container, the test bundle, starts the LdapConnectionConfigurationServiceTest service and properly injects the testObject.
Subsequently JUnit runs this test case, but creates another instance of this class. Which doesn't get the testObject injected, so I'm getting NullPointerExceptions.
Don't know what I'm missing... What I want is running the test case against an injected service provided by the OSGi framework.

Library for distributed spring config (outside springboot)

I am looking for solution for distributed spring configuration. I am thinking of storing it in zookeeper. https://github.com/spring-cloud/spring-cloud-zookeeper does have that functionality but apparently it requires to use spring-boot.
Is there any similar library that I can use outside spring-boot
Consul by HashiCorp
Consul is a popular option because it is:
Open Source
Includes Service Discovery & Configuration
Support Multi-Datacenter out of the box
Etc.
It doesn't require you to use Spring Boot, it just provides the auto-configurations in case you do decide to go with Spring Boot. In other words, if you're not using Spring Boot, none of the configurations will apply automatically, you'll have to provide the configuration yourself.
Zookeeper is a good option, go for it.
EDIT:
To use Zookeeper without Spring Boot, you'd need to register the appropriate beans either manually or by importing the auto-configuration classes that Spring Boot would import for you implicitly. This rule of thumb generally applies to all Spring Boot-enabled modules.
In your case, you'd most likely need to import just the ZookeeperConfigBootstrapConfiguration and ZookeeperConfigAutoConfiguration. The classes are to be found within spring-cloud-zookeeper-config module so no Spring Boot dependencies needed.
Alternatively, you should look at those classes and their #Imports and declare the beans manually.
I found a solution for using spring-cloud-zookeeper without Spring Boot, based on the idea provided here https://wenku.baidu.com/view/493cf9eba300a6c30d229f49.html
First, create a CloudEnvironement class that will create a PropertySource from Zookeeper :
CloudEnvironement.java
public class CloudEnvironment extends StandardServletEnvironment {
#Override
protected void customizePropertySources(MutablePropertySources propertySources) {
super.customizePropertySources(propertySources);
try {
propertySources.addLast(initConfigServicePropertySourceLocator(this));
}
catch (Exception ex) {
logger.warn("failed to initialize cloud config environment", ex);
}
}
private PropertySource<?> initConfigServicePropertySourceLocator(Environment environment) {
ZookeeperConfigProperties configProp = new ZookeeperConfigProperties();
ZookeeperProperties props = new ZookeeperProperties();
props.setConnectString("myzookeeper:2181");
CuratorFramework fwk = curatorFramework(exponentialBackoffRetry(props), props);
ZookeeperPropertySourceLocator propertySourceLocator = new ZookeeperPropertySourceLocator(fwk, configProp);
PropertySource<?> source= propertySourceLocator.locate(environment);
return source ;
}
private CuratorFramework curatorFramework(RetryPolicy retryPolicy, ZookeeperProperties properties) {
CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder();
builder.connectString(properties.getConnectString());
CuratorFramework curator = builder.retryPolicy(retryPolicy).build();
curator.start();
try {
curator.blockUntilConnected(properties.getBlockUntilConnectedWait(), properties.getBlockUntilConnectedUnit());
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
return curator;
}
private RetryPolicy exponentialBackoffRetry(ZookeeperProperties properties) {
return new ExponentialBackoffRetry(properties.getBaseSleepTimeMs(),
properties.getMaxRetries(),
properties.getMaxSleepMs());
}
}
Then create a custom XmlWebApplicationContext class : it will enable to load the PropertySource from Zookeeper when your webapplication start and replace the bootsrap magic of Spring Boot:
MyConfigurableWebApplicationContext.java
public class MyConfigurableWebApplicationContext extends XmlWebApplicationContext {
#Override
protected ConfigurableEnvironment createEnvironment() {
return new CloudEnvironment();
}
}
Last, in your web.xml file add the following context-param for using your MyConfigurableWebApplicationContext class and bootstraping your CloudEnvironement.
<context-param>
<param-name>contextClass</param-name>
<param-value>com.kiabi.config.MyConfigurableWebApplicationContext</param-value>
</context-param>
If you use a standard property file configurer, it should still be loaded so you can have properties in both a local file and Zookeeper.
For all this to work you need to have spring-cloud-starter-zookeeper-config and curator-framework jar in your classpath with their dependancy, if you use maven you can add the following to your pom.xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-zookeeper-dependencies</artifactId>
<version>1.1.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-config</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
</dependency>
</dependencies>

SpringBoot Couchbase Integration

I want to make a filterable list of my UserTask entity with the QueryDslPredicateExecutor interface, so the parameters given in the query string will be autoprocessed into a Predicate.
I have the following classes/interfaces
public interface UserTaskQuerydslRepository extends CrudRepository<UserTask, String>,
QueryDslPredicateExecutor<UserTask>, QuerydslBinderCustomizer<QUserTask> {
#Override
default void customize(QuerydslBindings bindings, QUserTask userTask) {
...
}
}
UserTask is my class that represents the (couchbase) model
#QueryEntity
#Document(expiry = 0)
public class UserTask {
#Id
private String id;
...
}
If i annotate this class with #QueryEntity then Maven generates the QUserTask class for me
#Generated("com.mysema.query.codegen.EntitySerializer")
public class QUserTask extends EntityPathBase<UserTask> {
private static final long serialVersionUID = 493434469L;
public static final QUserTask userTask = new QUserTask("userTask");
public final StringPath id = createString("id");
...
public QUserTask(String variable) {
super(UserTask.class, forVariable(variable));
}
public QUserTask(Path<? extends UserTask> path) {
super(path.getType(), path.getMetadata());
}
public QUserTask(PathMetadata<?> metadata) {
super(UserTask.class, metadata);
}
}
To generate QUserTask i added the following lines to pom.xml
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/apt</outputDirectory>
<processor>com.mysema.query.apt.jpa.JPAAnnotationProcessor</processor>
<processor>com.mysema.query.apt.QuerydslAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>3.4.3</version>
</dependency>
</dependencies>
</plugin>
In the project we have both JPA entities and couchbase entities, that's why i have the JPAAnnotationProcessor there.
If i run the application like this i get the following error:
org.springframework.data.mapping.PropertyReferenceException: No
property findAll found for type UserTask!
I tried to annotate my UserTaskQuerydslRepository with #NoRepositoryBean, it solved my findAll problem, but when i tries to #Inject this repository to a Resource (or controller, JHipster calls it Resource) i get the following error
No qualifying bean of type [.UserTaskQuerydslRepository]
found for dependency: expected at least 1 bean which qualifies as
autowire candidate for this dependency. Dependency annotations:
{#javax.inject.Inject()}
Can anyone help me what did I do wrong?
As #mp911de said in his comment, Spring Data Couchbase doesn't have support for QueryDsl, which explains why the bean cannot be created.
I can see where your confusion comes from when reading the doc. Chapter 5 is the content common to all Spring Data store implementations. All store documentations have one chapter with that same content, which generically talk about the repository basics. So it can mention things that are not in a particular implementation.
The first sentence of the section you linked even hints at it:
Several Spring Data modules offer integration with Querydsl via QueryDslPredicateExecutor.
Several, but not the Spring Data Couchbase module unfortunately.
2016. 07. 11. : After some research, and according to answers by #mp911de, and #simon-baslé we know that Spring Data Couchbase doesn't have support for QueryDsl yet.
I found a workaround for the problem that i wanted to solve (dynamic querying, aka. filters on a list and make it pageable)
https://github.com/TeamWanari/couchbase-query-executor

How to use weaven with aspectJ in compiletime in spring project

We are using Spring and we used Spring AOP. Due to the nature of Spring AOP which uses Proxy we reached the limitation of it when tring to warp join point on call inside a call.
i.e
aspect on B execution will not run if A is being call
public void A(){
B()
}
public void B(){
}
In order to solves this issue we are using ApsectJ weaven in compile time.
Which is work good. But then, the issue is make it play nice with Spring Bean i.e let the Autowired work in side the aspect class.
Pom.xml Maven plugin
<!-- AspectJ configuration -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<source>1.8</source>
<target>1.8</target>
<showWeaveInfo>true</showWeaveInfo>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
EDIT
duplicate of Spring autowired bean for #Aspect aspect is null
info on how to get aspectj to work with maven
Use AspectJ in compile time and make sure spring autowired magic will work
According to the AspectJ doc aspectOf Chapter. In order to some module to known that aspect is an aspect of something one should use aspectOf. Spring has the feature
<bean id="a" class="com.someinterface.A" factory-method="aspectOf"></bean>
This will result the A of above to be a Spring Bean and as a bonus Spring will know that this is an aspect of some other code. This is enough for Spring to use the Autowire magic inside of an aspect.
NOTE that using aspectOf requires xml configuration. I tried to get the same result with #Configurable but it did not work. if some one has some info on that it will great. :)
Bonus - Use Spring AOP proxy for aspect(in run time)
Set spring to scan #Aspect and make it a spring bean
<context:component-scan base-package="com.centure" >
<context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
</context:component-scan>
in this case every thing will work out of the box
private SomeService service;
public SomeService getService() {
return service;
}
#Autowired
public void setService(SomeService) {
this.service = service;
}
#Aspect
public class myAspect {
#Pointcut("execution(public * com.myinterface.save(..))")
public void save() {
}
#Around("myAspect () && args(thearg)")
public Object doBasicProfiling(ProceedingJoinPoint pjp, TheObject thearg)
throws Throwable {
Object retVal = null;
try {
retVal = pjp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
return retVal;
}

Annotation scan not scanning external jars in classpath

Issue: Spring Component Annotation scan not picking up the class annotated in the external jar which is not included in pom.xml. But i need to scan for classes with specific annotation from external jars. These external jars will be placed in the classpath but will not be known to my application during compile time.
1) We have a maven module(artifactId="metric_processor") which produces a jar file(metric_processor.jar) and has following classes
package com.metric;
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface ProcessMetric {
String name();
}
package com.metric;
public interface MetricProcessor {
int computeMetric();
}
package com.metric;
#ProcessMetric(name="LATENCY")
#Component
public class LatencyMetricProcessor implements MetricProcessor {
.....
}
2) We have another maven module ("artifactId="metric_processor_external") which produces a jar(metric_processor_external.jar) and includes "metric_processor" module as compile time scope.
package com.metric;
#ProcessMetric(name="TEST_METRIC_EXTERNAL")
#Component
public class TestMetricProcessor implements MetricProcessor {
....
}
3) We have a third(main) maven module(artifactId="main_application") which is a stand alone application(uses spring) which includes module "metric_processor" in compile scope. (But does not include "metric_processor_external"). The build plugin for the third module is
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.main.TriggerMetricProcessor</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Application context xml for this module is
<beans>
<context:component-scan base-package="com.metric">
<context:include-filter type="annotation" expression="com.metric.ProcessMetric" />
</context:component-scan>
<bean id="triggerMetricProcessor" class="com.main.TriggerMetricProcessor" />
</beans>
I have the following class which is the starting point of the application
package com.main;
import ...
public class TriggerMetricProcessor {
public static void main(String[] args) throws Exception {
ApplicationContext context =
new ClassPathXmlApplicationContext("application-context.xml");
TriggerMetricProcessor triggerMetricProcessor = (TriggerMetricProcessor) context.getBean("triggerMetricProcessor");
triggerMetricProcessor.initMetricProcessor(context);
}
private void initMetricProcessor(ApplicationContext context) {
GenericBeanFactoryAccessor beanFactoryAccessor = new GenericBeanFactoryAccessor(context);
final Map<String, Object> metricProcessors = beanFactoryAccessor.getBeansWithAnnotation(ProcessMetric.class);
for (final Object metricProcessor : metricProcessors.values()) {
final Class<? extends MetricProcessor> metricProcessorClass = (Class<? extends MetricProcessor>)metricProcessor.getClass();
final ProcessMetric annotation = metricProcessorClass.getAnnotation(ProcessMetric.class);
System.out.println("Found MetricProcessor class: " + metricProcessorClass + ", with name: " + annotation.name());
}
}
}
we compile the third module as
maven clean install assembly:single
This produces the jar file "main_application-with-dependencies.jar"
Then we run its as
java -cp "metric_process_external.jar" -jar main_application-with-dependencies.jar
Now the application finds only "LatencyMetricProcessor" and does not find the "TestMetricProcessor".
Can someone please help?
When you use the -jar option to execute a jar file, the -cp option is ignored.
The Oracle Java docs for the -jar option say:
-jar
Execute a program encapsulated in a JAR file. The first argument is
the name of a JAR file instead of a startup class name. In order for
this option to work, the manifest of the JAR file must contain a line
of the form Main-Class: classname. Here, classname identifies the
class having the public static void main(String[] args) method that
serves as your application's starting point. See the Jar tool
reference page and the Jar trail of the Java Tutorial for information
about working with Jar files and Jar-file manifests.
When you use this option, the JAR file is the source of all user
classes, and other user class path settings are ignored.
Also check out this post: stackoverflow.com/questions/5879925/in-linux-how-to-execute-java-jar-file-with-external-jar-files
So you'll need to specify the metric_process_external.jar in your manifest file using a Class-Path: header. You should be able to get your Maven assembly plugin to do that.
If that's not practical, you'll need to run your application without the -jar flag:
java -cp "metric_process_external.jar:main_application-with-dependencies.jar" com.main.TriggerMetricProcessor

Resources