Cannot start an OSGI bundle that embed spring boot in liferay 7 - spring

I want to develop a standalone bundle that implement a service using spring boot and spring data jpa (without web).
The bundle aims to create a spring context to facilitate the creation of Repository, and in teh bundle activator, I create the spring boot application, get an implementation of service that use the injected repository and this service will be registered as an OSGI service.
The bundle will be deployed on Liferay 7 so there is no ready bundles to help exporting packages (for jpa ...), to make simpler the idea is to have a standalone bundle that embed all dependencies in the bundle classpath (no package to import from outside the bundle)
Is there any sample that can help ? and is that a good idea ?
The problem was, when trying to start the bundle, it fails with "Caused by: java.lang.ClassNotFoundException: org.osgi.framework.BundleActivator .."
The following classes are simplified sampel to demonstates the problem (normally it must be a separate bundle that define and export the api that will be implemented by the bundle in question, but in this sample this is a unique bundle with 4 classes)
1/ The bundle activator class
import java.util.Hashtable;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.springframework.context.ApplicationContext;
public class Activator implements BundleActivator
{
#Override
public void start(BundleContext context) throws Exception
{
ApplicationContext springCtx = SpringFramework.getContext();
UserDao dao = springCtx.getBean(UserDao.class);
userDaoReg = bc.registerService(UserDao.class.getName(), dao, new Hashtable());
}
#Override
public void stop(BundleContext context) throws Exception
{
/** **/
}
}
2/ class to launch the spring boot application
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
#SpringBootApplication
public class SpringFramework {
private static ConfigurableApplicationContext context;
public static void main(String[] args) {
context = SpringApplication.run(SpringFramework.class);
}
public static ConfigurableApplicationContext getContext()
{
if (context == null) {
context = SpringApplication.run(SpringFramework.class);
}
return context;
}
}
3/ The UserDao to be registered as a service
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserDao extends JpaRepository<User, Integer>
{
}
4/ and a simple JPA Entity class "User"
And these are dependencies and plugin used in the pom.xml
<dependencies>
<!--OSGI dependencies-->
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<scope>provided</scope>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--persistence-api -->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.3.0.RELEASE</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Import-Package>!*</Import-Package>
<Bundle-Activator>hello.Activator</Bundle-Activator>
<Embed-Dependency>*</Embed-Dependency>
<!--<Embed-Transitive>true</Embed-Transitive>-->
</instructions>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
This is the generated manifest in the jar
Manifest-Version: 1.0
Bundle-SymbolicName: test-spring-boot-no-web
Archiver-Version: Plexus Archiver
Built-By: XXX
Bnd-LastModified: 1475774161783
Bundle-ManifestVersion: 2
Embed-Dependency: *
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
Spring-Boot-Version: 1.3.0.RELEASE
Tool: Bnd-3.2.0.201605172007
Main-Class: org.springframework.boot.loader.JarLauncher
Embedded-Artifacts: org.osgi.core-6.0.0.jar;g="org.osgi";a="org.osgi.c
ore";v="6.0.0",slf4j-api-1.7.13.jar;g="org.slf4j";a="slf4j-api";v="1.
7.13",spring-boot-starter-1.3.0.RELEASE.jar;g="org.springframework.bo
ot";a="spring-boot-starter";v="1.3.0.RELEASE",spring-boot-starter-dat
a-jpa-1.3.0.RELEASE.jar;g="org.springframework.boot";a="spring-boot-s
tarter-data-jpa";v="1.3.0.RELEASE",persistence-api-1.0.2.jar;g="javax
.persistence";a="persistence-api";v="1.0.2",javax.transaction-api-1.2
.jar;g="javax.transaction";a="javax.transaction-api";v="1.2"
Export-Package: hello;version="1.0.0"
Bundle-Name: spring-boot-no-web
Bundle-Version: 1.0.0.SNAPSHOT
Bundle-ClassPath: .,org.osgi.core-6.0.0.jar,slf4j-api-1.7.13.jar,sprin
g-boot-starter-1.3.0.RELEASE.jar,spring-boot-starter-data-jpa-1.3.0.R
ELEASE.jar,persistence-api-1.0.2.jar,javax.transaction-api-1.2.jar
Bundle-Activator: hello.Activator
Start-Class: hello.SpringFramework
Created-By: Apache Maven Bundle Plugin
Build-Jdk: 1.8.0_101

I saw 2 questions in your post so I'll try to answer those:
Is there any sample that can help ?
I don't think so! What you are trying to do seems weird to me. See below for details.
... is that a good idea ?
You are saying you want "standalone bundle" that "will be deployed on Liferay 7"! It may be you just picked the wrong words but the way you state it, you are trying to have mutually exclusive things.
There is no such thing as "standalone bundle". I assume you mean standalone java application (executable Jar file that has the OSGi framework embedded). You can build such applications in a number of different ways. For example there is excellent tutorial how to do this from EnRoute. You can not however deploy such executable jar as it typically is not a OSGi bundle. While technically you can make it a bundle, you may run into all kinds of issues due to the embeded runtime and dependencies.
In Liferay 7 (and any outher product that has OSGi container) you can run a bundle in the runtime environment the product defines. The bundle must be resolvable at runtime. It may have all it's dependencies embedded but that defeats the purpose of modularity unless it provides something to outher bundles (which does not seem to be your case).
From that perspective what you are trying to do seems to be a bad idea. Moreover Spring Boot is a framework to build stand alone java applications and as such have it's own assumptions. Making it work inside an OSGi container is likely not a trivial task (if at all possible)
Perhaps better idea would be to have some bundles providing the business logic only. Then you could deploy those bundles in Liferay and laverage Liferay's capabilities to serve REST servces. You could use the exact same bundles to cunstruct standalone application that uses Spring or CXF or something else.
Notes about your code
your main class is org.springframework.boot.loader.JarLauncher. If you run this jar it will start Spring which likely will be totally unaware of OSGI runtime.
you have org.osgi.core-6.0.0.jar is your bundle's classpath with is basically the OSGi's runtime. This will cause issues if deployed into a OSGi runtime and my be the reason why you see
Caused by: java.lang.ClassNotFoundException: org.osgi.framework.BundleActivator ..

Related

Springboot JPA with Tomcat 7

I have been trying to deploy springboot with JPA on Tomcat 7. The app works fine when running with java -jar. But with deployed on Tomcat, it is often saying can't find the bean with extended JpaRepository interface.
What is the proper way to deploy springboot on Tomcat 7?
Thanks in advance.
some times this will helps
in Application.java
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
public class Application extends SpringBootServletInitializer
Add this Dependency and Plugin to pom.xml
<!--For Build War File-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
This works for me
Hope this will helps...!

Spring Boot - Spring Data REST generate swagger documentation from repository

I have an application in Spring Boot with Spring Data Rest and I am trying to generate the documentation with Swagger using swagger-maven-plugin. The Controller documentation is generated without problems but the repository does not.
I have configured the swagger-maven-plugin of the following form in my pom.xml:
<plugin>
<groupId>com.github.kongchen</groupId>
<artifactId>swagger-maven-plugin</artifactId>
<version>3.1.6</version>
<configuration>
<apiSources>
<apiSource>
<springmvc>true</springmvc>
<locations>
<location>com.abelendo.repository</location>
<location>com.abelendo.controller</location>
</locations>
<schemes>http</schemes>
<host>localhost:8080</host>
<basePath>/</basePath>
<info>
<title>Swagger Maven Plugin Spring Boot for cars</title>
<version>v1</version>
<description>Working sample of Spring Boot for cars annotations</description>
<termsOfService>
http://www.github.com
</termsOfService>
<contact>
<email>abelendo#email.com</email>
<name>Abelendo Cars</name>
<url>http</url>
</contact>
<license>
<url>http://www.license.com</url>
<name>License name</name>
</license>
</info>
<!-- Support classpath or file absolute path here.
1) classpath e.g: "classpath:/markdown.hbs", "classpath:/templates/hello.html"
2) file e.g: "${basedir}/src/main/resources/markdown.hbs",
"${basedir}/src/main/resources/template/hello.html" -->
<templatePath>${basedir}/templates/strapdown.html.hbs</templatePath>
<outputPath>${basedir}/generated/document.html</outputPath>
<outputFormats>yaml</outputFormats>
<swaggerApiReader>com.github.kongchen.swagger.docgen.reader.SpringMvcApiReader</swaggerApiReader>
<swaggerDirectory>generated/swagger-ui</swaggerDirectory>
</apiSource>
</apiSources>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
My CarRepository:
#Api(tags = "CarsRepo")
#RepositoryRestResource(path = "cars")
public interface CarRepository extends CrudRepository<Car, Long> {
<S extends Car> S save(#Valid S cars);
}
Is it possible to generate the repository documentation with swagger-maven-plugin?
In order to generate swagger documentation for a #RepositoryRestResource, all you need to do is:
Pull the io.springfox:springfox-data-rest dependency in your project
Import the springfox.documentation.spring.data.rest.configuration.SpringDataRestConfiguration class in your swagger configuration class.
#Configuration
#EnableSwagger2
#Import(SpringDataRestConfiguration.class)
public class SwaggerConfig {
#Bean
public Docket api() { ... }
}
Edit: the swagger config class doesn't work with spring-boot 2.0, spring-data 2.0 and spring-data-rest 3.0: there's an open issue in swagger (linked to swagger not being Java8 while spring-boot and spring-data are). See here for details: https://github.com/springfox/springfox/issues/2298.
However, I managed to solve it by patching a few swagger classes. The idea behind the patch is to use Java Optional instead of Guava and Java reflection. The patched classes are:
springfox.documentation.spring.data.rest.EntityServicesProvider
springfox.documentation.spring.data.rest.EntityContext
springfox.documentation.spring.data.rest.EntityDeleteExtractor
springfox.documentation.spring.data.rest.EntityFindAllExtractor
springfox.documentation.spring.data.rest.EntityFindOneExtractor
springfox.documentation.spring.data.rest.EntitySaveExtractor
I just 1 dependency in pom.xml
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-data-rest -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-data-rest</artifactId>
<version>3.0.0</version>
</dependency>
Then import #Import(SpringDataRestConfiguration.class) in Respository
and it generates documentation

Adding Spring (Boot?) to existing RESTEasy JAX-RS application

I have an existing Maven project based on JAX-RS using RESTEasy. It works great! It creates a WAR that I deploy to Tomcat running on Ubuntu. It's clean and follows the latest standards. The POM is simple:
...
<packaging>war</packaging>
...
<dependencies>
...
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-servlet-initializer</artifactId>
<version>3.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
<version>3.1.0.Final</version>
</dependency>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
...
I don't need any web.xml because I'm using the latest Java EE annotations:
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#ApplicationPath("/")
public class MyRESTApplication extends Application {
final FooResource fooResource = new FooResourceService();
...
#Override
public Set<Object> getSingletons() {
return ImmutableSet.of(fooResource);
}
}
This is all simple and it's working so great! Now I just want a way to easily change FooResource implementations based on the profile --- in other words, wire my singletons. That's where Spring comes in, right? And I've been told that Spring Boot makes Spring even more awesome, and you can use it with anything, and it gives you an actuator that allows you to gain real-time inside on the health of your system.
Unfortunately all the Spring Boot books and tutorials seem to think I'm starting with one of their quick-start applications. But I already have a great, simple application. I just want to:
Get my application wiring, based on profiles, from an external configuration file (not annotations) via Spring.
Get whatever other goodness comes from Spring Boot, because apparently it is awesome and will completely transform my application.
How do I add Spring (or Spring Boot) to this simple little JAX-RS application?
we solved it that way, that we created a singleton spring bean, let's call it ServiceStartupClass, where we register all JAX-RS services.
Here some code snippet how we start our services:
import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.server.ResourceConfig;
#Component
#ApplicationPath("/")
public class ServiceStartupClass extends ResourceConfig {
#PostConstruct
public void startup() {
register(FooResource.class);
...
}
}
If you need any further help, let me know

aspectj maven joinpoint advised but advice not called

Before marking this question as a duplicate, please read through, as
I've gone through a number of posts on SO and other places but have
still failed to find a solution to my problem.
I'm trying to implement a project in Spring + AspectJ and as the title says, I can see the aspectj maven plugin applying the advice but it isn't actually called.
I'm trying to apply an advice based on an annotation.
Following is the annotation class:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface LogThis {
String name();
int id();
int eventID();
}
This annotation has been applied to a method which is being called from a js script on the front end through an ajax call. The method being called is as follows:
#RequestMapping(value = "/handle", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.NO_CONTENT)
#LogThis(name = "name", ID = 12345, eventID = 12345)
public void create(#RequestBody TodoDTO todo, HttpServletRequest req) {
//perform some action
}
The advice is being applied to the LogThis annotation and the advice is as follows:
#Pointcut("#annotation(LogThis)")
public void genericPointcut() {
}
#Pointcut("execution(* *(..))")
public void atExecution() {
}
#Async
#Before("genericPointcut() && atExecution()")
public void logBefore(JoinPoint joinPoint) throws NoSuchMethodException, SecurityException {
// Perform logging
}
The annotation class and the aspect are in the same package while the class which is being advised is in a different package but everything is in the same project.
I've configured my maven pom.xml file as follows (only relevant portions shown):
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.8</version>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
<source>${java.source-target.version}</source>
<target>${java.source-target.version}</target>
<Xlint>ignore</Xlint>
<complianceLevel>${java.source-target.version}</complianceLevel>
<encoding>${project.build.sourceEncoding}</encoding>
<verbose>true</verbose>
</configuration>
<executions>
<execution>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.2</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
The properties are:
<properties>
<sonar.language>java</sonar.language>
<java.source-target.version>1.7</java.source-target.version>
<aspectj.version>1.8.7</aspectj.version>
</properties>
The aspectj dependencies are:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
Spring version being used is 4.1.3.RELEASE.
The spring config entry for my aspect is as follows:
<aop:aspectj-autoproxy />
<bean id="logAspect" class="somep2.LoggingAspect" />
On running mvn clean install the build succeeds and the following log entry is present w.r.t aspectj:
[INFO] --- aspectj-maven-plugin:1.8:compile (default) # myproj ---
[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
[INFO] Join point 'method-execution(void somep.SomeC.create(param1, param2))' in Type 'somep.SomeC' (SomeC.java:63) advised by before advice from 'somep2.LoggingAspect' (LoggingAspect.java:36)
[INFO]
[INFO] --- aspectj-maven-plugin:1.8:test-compile (default) # myproj ---
[WARNING] No sources found skipping aspectJ compile
According to the logs, the join point was found and advised but the logBefore() method is never called when the create() method is called. I am certain of this because I'm writing to a file using a FileWriter but nothing is being written.
Deployment details:
This project is built as part of another project which creates an ear file which is then deployed on JBoss 6.3
I've tried numerous approaches but nothing has worked. Please let me know what I'm missing.
Any help is appreciated.
I finally got it to work. Turns out I was complicating things too much. There was no need for the aspectj compiler. All that I had to do was tell spring that my aspect was a component as well so that it could inject my advice.
So here's the complete list of changes:
Removed the aspectj-maven-plugin from pom.xml. It is not required.
Removed the aspectj-tools and spring-aop dependencies and added the aspectj-weaver dependency to pom.xml
Removed the bean entry for my aspect from the spring config.
Annotated my aspect class with #Component and made sure that it was being scanned as part of the Spring component scan.
Hope this helps someone else as well.
PS. I still do not completely understand why this worked so if someone has an explanation, please comment.

Error while trying to use an API. java.lang.NoSuchFieldError: INSTANCE

I am trying to connect to the smartsheet api using a java program.
Initially I had problems with the site certificate which was resolved by adding it to the java keystore. Now when I am trying to run my code, I get the following error.
Exception in thread "main" java.lang.NoSuchFieldError: INSTANCE
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.<clinit>(SSLConnectionSocketFactory.java:144)
at org.apache.http.impl.client.HttpClientBuilder.build(HttpClientBuilder.java:955)
at org.apache.http.impl.client.HttpClients.createDefault(HttpClients.java:58)
at com.smartsheet.api.internal.http.DefaultHttpClient.<init>(DefaultHttpClient.java:64)
at com.smartsheet.api.SmartsheetBuilder.build(SmartsheetBuilder.java:203)
at SmartsheetConnection.main(SmartsheetConnection.java:13)
This is my code (I followed their documentation).
import com.smartsheet.api.*;
import com.smartsheet.api.models.*;
import com.smartsheet.api.models.enums.*;
import com.smartsheet.api.oauth.*;
public class SmartsheetConnection {
public static void main(String[] args) throws SmartsheetException {
// Set the access token.
Token token = new Token();
token.setAccessToken("foo");
Smartsheet smartsheet = new SmartsheetBuilder().setAccessToken(token.getAccessToken()).build();
}
}
The line that is throwing error is (line 144)
#Deprecated
public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER
= AllowAllHostnameVerifier.INSTANCE;
but I am not sure what to make of it. I am using maven to get the dependencies. Does it have something to do with the version of the Apache HttpComponents?
Here is the pom.xml
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.smartsheet</groupId>
<artifactId>smartsheet-sdk-java</artifactId>
<version>2.0.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-apache-client</artifactId>
<version>1.9</version>
</dependency>
</dependencies>
Other posts about this error seem to suggest that it's typically caused by conflicting versions of httpcore jar. i.e., an older version of httpcore on the classpath.
For more information, I'd suggest you checkout the following posts:
java.lang.NoSuchFieldError: org.apache.http.message.BasicLineFormatter.INSTANCE from Mashape Unirest in Java application
java.lang.NoSuchFieldError: INSTANCE
I know its I am replying a bit late actually I am also struggling the same problem and I found the solution by using Maven Shade plugin.
The Problem is the JAR conflict probably your project is using a different Version Of HTTPclient then your container over which your Appliaction is running.
To resolve this use the Below Maven Shade Plugin which will change the package name of HttpClient to the specified one which packaging the JAR. This will also refactor all the usage in your code.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>org.apache.http</pattern>
<shadedPattern>org.shaded.apache.http</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
The Above sample will change HttpClient Package with org.shaded.apache.http from org.apache.http
Maven Shade will also create a fat/uber jar so your final package size get increased and will have all the classes which you have mentioned in the Dependency in POM.
If you don't want to include the all your dependency jar in your final jar then add the Scope for the Dependency as <scope>provided</scope>.
the reason for this problem is:
org.apache.http.conn.ssl.AllowAllHostnameVerifier class,which is execused in the runtime,has no field 'INSTANCE'.
My project classpath contains two same name class of "org.apache.http.conn.ssl.AllowAllHostnameVerifier".
One cames from a jar customized by our company,which has no field 'INSTANCE'.
Another cames from maven central repository,which has the field 'INSTANCE'.
My code sometimes run the logic of the latter jar and sometimes the fromer jar,which is the reason I guessed.
my classpath search result
the comparison of the two jar
I was using intellij for both android and spring development.
In my case, I accidentally chose Android sdk as the module SDK.
After choosing JDK 1.8 and rebuilding the project fixed the issue for me

Resources