Deploying Spring Boot 2.x Applications in WebLogic 12.1.3.1

Deploying Spring Boot 2.x Applications in WebLogic Versions 12.2.x is simple then deploying those in WebLogic 12.1.x. I was struggling on the deployment of 2.x applications in 12.1.x version of WebLogic using Gradle. There is no issue if you use Maven. But, using gradle is complicated. But, finally, I got the solution and deployed successfully.

Today, I will demonstrate how to deploy 2.x applications in 12.1.x version of WebLogic. Let's start.

1. Create a project from https://start.spring.io/

Once you download your project, you will see below contents in build.gradle. I've already added the configurations to deploy on WebLogic Servers. 

buildscript {

    ext {
        springBootVersion = '2.1.1.RELEASE'
    }

    repositories {
        mavenCentral()
    }

    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("javax.servlet:javax.servlet-api:4.0.1")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse-wtp'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'war'

group = 'com.app'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

configurations {
    providedRuntime
    compile.exclude module: 'spring-boot-starter-tomcat'
}

dependencies {
    implementation('org.springframework.boot:spring-boot-starter-actuator')
    implementation('org.springframework.boot:spring-boot-starter-web')

    providedCompile('javax.servlet:javax.servlet-api:4.0.1')

    providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')
    testImplementation('org.springframework.boot:spring-boot-starter-test')
}

There are some more configuration that needs to be done. I'm not going one by one here. Please check my earlier post on this.

Let's deploy now. You will see below error:

Output Message From WebLogic Console:: 

<AppMerge failed to merge your application. If you are running AppMerge on the command-line, merge again with the -verbose option for more details.

Output on WebLogic Web Console:

Unable to access the selected application.

Error java.io.IOException

Error weblogic.utils.compiler.ToolFailureException

For this, there was a bug (which was not a bug) post reported in Spring Boot Github Repo and following was the reply from one of the known Spring Boot Developer, Andy Wilkinson.

"Spring Boot 2.0 requires Java 8. It would appear that your WebLogic Server, specifically the repackaged version of ASM that it is using, doesn’t support Java 8. If you are not in a position to upgrade WebLogic you’ll have to stick with Spring Boot 1.5."

So, I tried applying ASM patch from 12.2.x version. But, still it didn't worked. Then, I came to know that it is because of the incompatible log version which is by default added in Spring Boot: 

spring-boot-starter-logging

2. Exclude spring-boot-starter-logging:

...
...
...
configurations {
    providedRuntime
    compile.exclude module: 'spring-boot-starter-tomcat'
    all*.exclude module: 'spring-boot-starter-logging'
}
...
...
...

But, still deployment failed.

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
<Dec 15, 2018 1:22:37 PM CST> <Error> <org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter> <BEA-000000> <
***************************
APPLICATION FAILED TO START
***************************
...
...
...
Action:
Correct the classpath of your application so that it contains a single, compatible version of javax.validation.Configuration
<Dec 15, 2018 1:22:38 PM CST> <Error> <Deployer> <BEA-149265> <Failure occurred in the execution of deployment request with ID "101354633372978" for task "0". Error is: "weblogic.application.ModuleException: java.lang.NoSuchMethodException
javax.validation.Configuration.getDefaultParameterNameProvider()Ljavax/validation/ParameterNameProvider;"
weblogic.application.ModuleException: java.lang.NoSuchMethodError: javax.validation.Configuration.getDefaultParameterNameProvider()Ljavax/validation/ParameterNameProvider;
        at weblogic.application.internal.ExtensibleModuleWrapper.start(ExtensibleModuleWrapper.java:140)
        at weblogic.application.internal.flow.ModuleListenerInvoker.start(ModuleListenerInvoker.java:124)
        at weblogic.application.internal.flow.ModuleStateDriver$3.next(ModuleStateDriver.java:216)
        at weblogic.application.internal.flow.ModuleStateDriver$3.next(ModuleStateDriver.java:211)
        at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:42)
        Truncated. see log file for complete stacktrace
Caused By: java.lang.NoSuchMethodError: javax.validation.Configuration.getDefaultParameterNameProvider()Ljavax/validation/ParameterNameProvider;
        at org.springframework.validation.beanvalidation.LocalValidatorFactoryBean.configureParameterNameProvider(LocalValidatorFactoryBean.java:314)
        at org.springframework.validation.beanvalidation.LocalValidatorFactoryBean.afterPropertiesSet(LocalValidatorFactoryBean.java:290)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1804)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1741)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:576)
        Truncated. see log file for complete stacktrace

3. Add validation dependency:

dependencies {
    ...
    providedCompile('javax.servlet:javax.servlet-api:4.0.1')
    compile('javax.validation:validation-api:2.0.1.Final')
    ...
}

Still, deployment failed with below errors:

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
<Dec 15, 2018 1:36:41 PM CST> <Error> <org.springframework.boot.SpringApplication> <BEA-000000> <Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'defaultValidator' defined in class path resource [org/springframework/boot/autoconfigure/validation/ValidationAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.validation.beanvalidation.LocalValidatorFactoryBean]: Factory method 'defaultValidator' threw exception; nested exception is java.lang.NoClassDefFoundError: javax/el/ELManager
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:627)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:456)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1288)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538)
        Truncated. see log file for complete stacktrace

Caused By: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.validation.beanvalidation.LocalValidatorFactoryBean]: Factory method 'defaultValidator' threw exception; nested exception is java.lang.NoClassDefFoundError: javax/el/ELManager
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:456)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1288)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127)
        Truncated. see log file for complete stacktrace
Caused By: java.lang.NoClassDefFoundError: javax/el/ELManager
        at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.buildExpressionFactory(ResourceBundleMessageInterpolator.java:88)
        at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.<init>(ResourceBundleMessageInterpolator.java:47)
        at org.hibernate.validator.internal.engine.ConfigurationImpl.getDefaultMessageInterpolator(ConfigurationImpl.java:474)
        at org.springframework.boot.validation.MessageInterpolatorFactory.getObject(MessageInterpolatorFactory.java:54)
        at org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration.defaultValidator(ValidationAutoConfiguration.java:57)
        Truncated. see log file for complete stacktrace

4. Add el-api dependency:

dependencies {
    ...
    compile('javax.el:javax.el-api:3.0.0')
    ...
}

But, still it got failed with below errors:

Caused by: java.lang.IllegalAccessError: javax/el/ELUtil
        at javax.el.ELManager.getExpressionFactory(ELManager.java:61)
        at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.buildExpressionFactory(ResourceBundleMessageInterpolator.java:88)
        at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.<init>(ResourceBundleMessageInterpolator.java:47)
        at org.hibernate.validator.internal.engine.ConfigurationImpl.getDefaultMessageInterpolator(ConfigurationImpl.java:474)
        at org.springframework.boot.validation.MessageInterpolatorFactory.getObject(MessageInterpolatorFactory.java:54)
        at org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration.defaultValidator(ValidationAutoConfiguration.java:57)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
        ...

5. After some research, I came to know that this error was because of incompatible issue of hibernate-validator. Add below dependency in build.gradle and try deploying. This time the application will deploy successfully.

dependencies {
    ...
    ...
    compile('org.hibernate:hibernate-validator:5.4.1.Final')
    ...
    ...
}

 .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.1.RELEASE)

Dec 15, 2018 1:43:56 PM org.springframework.boot.StartupInfoLogger logStarting
INFO: Starting ServletInitializer on *** with PID 15804 (C:\Users\***\Documents\Oracle\user_projects\domains\***\servers\AdminServer\tmp\_WL_user\spring-boot-2x-demo-0.0.1-SNAPSHOT\emnq38\war\WEB-

.jar started by *** in C:\Users\***\Documents\Oracle\user_projects\domains\***)

Dec 15, 2018 1:43:56 PM org.springframework.boot.SpringApplication logStartupProfileInfo
INFO: No active profile set, falling back to default profiles: default
Dec 15, 2018 1:44:00 PM org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext prepareWebApplicationContext
INFO: Root WebApplicationContext: initialization completed in 3152 ms
Dec 15, 2018 1:44:02 PM org.springframework.scheduling.concurrent.ExecutorConfigurationSupport initialize
INFO: Initializing ExecutorService 'applicationTaskExecutor'
Dec 15, 2018 1:44:03 PM org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver <init>
INFO: Exposing 2 endpoint(s) beneath base path '/actuator'
Dec 15, 2018 1:44:03 PM org.springframework.boot.StartupInfoLogger logStarted
INFO: Started ServletInitializer in 7.442 seconds (JVM running for 1452.507)
Dec 15, 2018 1:44:34 PM org.springframework.web.servlet.FrameworkServlet initServletBean
INFO: Initializing Servlet 'dispatcherServlet'
Dec 15, 2018 1:44:34 PM org.springframework.web.servlet.FrameworkServlet initServletBean

INFO: Completed initialization in 24 ms

<Dec 15, 2018 1:44:41 PM CST> <Warning> <Socket> <BEA-000449> <Closing the socket, as no data read from it on 0:0:0:0:0:0:0:1:57,128 during the configured idle timeout of 5 seconds.>

This time application deployed successfully. To test this deployment, I've added actuator library. Go ahead and access the below URL.

http://localhost:7103/app/api/actuator

You should see below output:

{
    "_links": {
        "self": {
            "href": "http://localhost:7103/app/api/actuator",
            "templated": false
        },
        "health": {
            "href": "http://localhost:7103/app/api/actuator/health",
            "templated": false
        },
        "health-component": {
            "href": "http://localhost:7103/app/api/actuator/health/{component}",
            "templated": true
        },
        "health-component-instance": {
            "href": "http://localhost:7103/app/api/actuator/health/{component}/{instance}",
            "templated": true
        },
        "info": {
            "href": "http://localhost:7103/app/api/actuator/info",
            "templated": false
        }
    }
}

Final build.gradle contents:

buildscript {
    ext {
        springBootVersion = '2.1.1.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("javax.servlet:javax.servlet-api:4.0.1")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse-wtp'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'war'

group = 'com.app'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

configurations {
    providedRuntime
    compile.exclude module: 'spring-boot-starter-tomcat'
    all*.exclude module: 'spring-boot-starter-logging'
}

dependencies {
    implementation('org.springframework.boot:spring-boot-starter-actuator')
    implementation('org.springframework.boot:spring-boot-starter-web')

    providedCompile('javax.servlet:javax.servlet-api:4.0.1')

    compile('javax.validation:validation-api:2.0.1.Final')
    compile('javax.el:javax.el-api:3.0.0')
    compile('org.hibernate:hibernate-validator:5.4.1.Final')

    providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')
    testImplementation('org.springframework.boot:spring-boot-starter-test')
}

NOTE: Don't forget to add weblogic.xml file. Checkout the contents of weblogic.xml

You can find the full project from my Github Repo.

If you encounter any issues, please comment. I will try to help you. Happy Coding!!! 🙂 

Spring Security 5 Form Login with Database Provider
REST Architectural Constraints