본문 바로가기

WAS/WebLogic

애플리케이션 배치 시, AppMerge failed to merge your application

728x90

=============================

https://velog.io/@kimsw3445/BEA-160228-AppMerge-Failed

https://www.baeldung.com/java-find-class-version

=============================

일단 원인으로는 배포하려는 WebApplication의 라이브러리가

현재 weblogic을 동작시키고 있는 JDK 버전과 충돌나서 발생하는 현상으로 보인다.

즉, 컴파일이 된 class 파일의 JDK 버전과 운영중인 WebLogic의 JDK 버전과

상충되기에 발생한 현상으로 보인다.

 

<Jun 20, 2024 3:35:20,418 PM KST> <Error> <J2EE> <BEA-160228> 
<AppMerge failed to merge your application. 
If you are running AppMerge on the command-line, merge again with the -verbose option for more details. 
See the error message(s) below.>
weblogic.utils.compiler.ToolFailureException: 
Apps tool failure: Check nested exception for details
        at weblogic.application.compiler.FlowDriver.handleStateChangeException(FlowDriver.java:55)
        at weblogic.application.compiler.FlowDriver.nextState(FlowDriver.java:38)
        at weblogic.application.compiler.AppMerge.runBody(AppMerge.java:168)

        at com.bea.netuix.nf.ControlTreeWalker.walkRecursive(ControlTreeWalker.java:334)
        at com.bea.netuix.nf.ControlTreeWalker.walkRecursive(ControlTreeWalker.java:334)
        at com.bea.netuix.nf.ControlTreeWalker.walkRecursive(ControlTreeWalker.java:334)
        at com.bea.netuix.nf.ControlTreeWalker.walkRecursive(ControlTreeWalker.java:334)
        at com.bea.netuix.nf.ControlTreeWalker.walkRecursive(ControlTreeWalker.java:334)
        at com.bea.netuix.nf.ControlTreeWalker.walkRecursive(ControlTreeWalker.java:334)
        at com.bea.netuix.nf.ControlTreeWalker.walkRecursive(ControlTreeWalker.java:334)
        at com.bea.netuix.nf.ControlTreeWalker.walkRecursive(ControlTreeWalker.java:334)
        at com.bea.netuix.nf.ControlTreeWalker.walk(ControlTreeWalker.java:130)
        at com.bea.netuix.nf.Lifecycle.processLifecycles(Lifecycle.java:399)
        at com.bea.netuix.nf.Lifecycle.processLifecycles(Lifecycle.java:361)
        at com.bea.netuix.nf.Lifecycle.processLifecycles(Lifecycle.java:352)
  		...

        at weblogic.work.ExecuteThread.execute(ExecuteThread.java:420)
        at weblogic.work.ExecuteThread.run(ExecuteThread.java:360)

Caused by: java.lang.IllegalArgumentException
        at com.bea.objectweb.asm.ClassReader.<init>(Unknown Source)
        at com.bea.objectweb.asm.ClassReader.<init>(Unknown Source)
        at weblogic.application.utils.annotation.ClassInfoImpl.<init>(ClassInfoImpl.java:85)
        at weblogic.application.utils.annotation.ClassInfoImpl.<init>(ClassInfoImpl.java:79)
        ...
        at weblogic.application.utils.AnnotationDetector.scan(AnnotationDetector.java:172)
   		 
        ... 116 more

 

라이브러리 체킹 관련해서는 javap -v ${CLASS_FILE} | grep major 를 검색하며 하나하나 찾아봐야 한다.

하나하나 다 보기 귀찮다면, 아래의 코드는 chatGPT의 질의를 하고 얻은 스크립트다

지금 테스트 해봤는데 sh 파일 하나 만들고 실행하였고, nohup.out 파일에 tail -f 걸면서 보는데 잘 쌓인다.

#!/bin/bash

# 결과를 저장할 파일 지정
output_file="nohup.out"

# 결과 파일 초기화
> "$output_file"

# 전체 경로에서 .class 파일을 찾아서 반복문 실행
find . -type f -name "*.class" | while read -r classfile; do
    # javap -v 명령어를 실행하여 major 버전 추출
    major_version=$(javap -v "$classfile" | grep 'major version')

    # 결과 출력
    echo "File: $classfile" >> "$output_file"
    echo "$major_version" >> "$output_file"
    echo "----------------------" >> "$output_file"

    # CPU 사용량을 줄이기 위해 약간의 지연 추가
    sleep 0.1
done

 

# for window server PowerShell
# 결과를 저장할 파일 지정
$outputFile = "nohup.out"

# 결과 파일 초기화
Out-File -FilePath $outputFile -Force

# 전체 경로에서 .class 파일을 재귀적으로 찾기
Get-ChildItem -Path . -Recurse -Filter *.class | ForEach-Object {
    $classFile = $_.FullName

    # javap -v 명령어를 실행하여 major 버전 추출
    $majorVersion = javap -v $classFile | Select-String -Pattern 'major version'

    # 결과 출력
    "File: $classFile" | Out-File -FilePath $outputFile -Append
    "$majorVersion" | Out-File -FilePath $outputFile -Append
    "----------------------" | Out-File -FilePath $outputFile -Append

    # CPU 사용량을 줄이기 위해 약간의 지연 추가
    Start-Sleep -Milliseconds 100
}

#이 스크립트를 백그라운드에서 실행하고, 출력을 nohup.out에 저장하려면 다음 단계를 따르세요:

1#.스크립트를 파일로 저장하세요. 예를 들어 CheckMajorVersion.ps1로 저장합니다.
2#.PowerShell을 관리자 권한으로 실행합니다.
3#.스크립트가 저장된 디렉토리로 이동합니다:
cd C:\path\to\script
4#. Start-Process powershell -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File .\CheckMajorVersion.ps1" -NoNewWindow -RedirectStandardOutput "nohup.out" -RedirectStandardError "nohup.out"

 

 

그리고 배포를 관리 콘솔이 아니라 weblogic.Deployer를 통해서 배포를 시도할 때,

DEBUG 레벨로 로깅을 설정하면 생각보다 쉽게 원인을 찾을 수가 있다. 

[app@test1 bin]$ . ./setDomainEnv.sh
#java weblogic.Deployer -adminurl <관리콘솔주소:PORT> -username <콘솔계정ID> -password <콘솔PWD> -deploy <APP경로> -name <APP이름> -nostage -targets <타겟_인스턴스> -verbose -debug
[app@test1 bin]$ java weblogic.Deployer -adminurl xxx.xxx.xx.xxx:7001 -username weblogic -password weblogic11! -deploy /libtest -name libtest -nostage -targets M1 -verbose -debug


[BasicOperation.execute():517] : Initiating deploy operation for app, libtest, on targets:
[BasicOperation.execute():519] :    M1
Task 4 initiated: [Deployer:149026]deploy application libtest on M1.
dumping Exception stack
Task 4 failed: [Deployer:149026]deploy application libtest on M1.
Target state: deploy failed on Server M1
java.lang.UnsupportedClassVersionError: 
com/example/HelloServlet has been compiled by a more recent version of the Java Runtime 
(class file version 55.0), 
this version of the Java Runtime only recognizes class file versions up to 52.0
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
        at weblogic.utils.classloaders.GenericClassLoader.defineClassInternal(GenericClassLoader.java:1113)
        at weblogic.utils.classloaders.GenericClassLoader.defineClass(GenericClassLoader.java:1046)
        at weblogic.utils.classloaders.GenericClassLoader.findLocalClass(GenericClassLoader.java:1038)

 

JDK1.8로 설치한 WAS에 JDK 11 버전의 class 파일이 있어서 생긴 문제라는 것을 바로 보여준다.

 

부록으로 class version에 대한 글을 보면 다음과 같다.

## .class Version in Java

Java SE 18 62 003e
Java SE 17 61 003d
Java SE 16 60 003c
Java SE 15 59 003b
Java SE 14 58 003a
Java SE 13 57 0039
Java SE 12 56 0038
Java SE 11 55 0037
Java SE 10 54 0036
Java SE 9 53 0035
Java SE 8 52 0034
Java SE 7 51 0033
Java SE 6 50 0032
Java SE 5 49 0031
JDK 1.4 48 0030
JDK 1.3 47 002f
JDK 1.2 46 002e
JDK 1.1 45 002d

 

 

아래 글은 위의 링크에서 퍼온 글이다.

=====

검색 및 시도


해당 내용을 검색하자 Weblogic 업그레이드시(JAVA6 -> JAVA8) 발생하는 경우, JPA 2.1 사용, lib classpath 등의 케이스가 존재하였다.

JPA2.1


weblogic 12.1.3은 기본적으로 JPA2.1 버전을 지원하지 않는다. 하지만 JPA2.1을 사용하는 어플리케이션을 위해 별도의 CLASSPATH를 지정해주어 해당 어플리케이션 배포를 가능하게 할 수 있다.

cd ${DOMAIN_HOME}/bin/
vi setDomainEnv.sh
PRE_CLASSPATH=${ORACLE_HOME}/oracle_common/modules/javax.persistence_2.1.jar:${ORACLE_HOME}/wlserver/modules/com.oracle.weblogic.jpa21support_1.0.0.0_2-1.jar

위 설정 후에도 해당 환경에서는 정상적으로 배포가 되지 않았다.

JDK release 변경


jdk1.8.0_201 -> jdk1.8.0_321

cd ${DOMAIN_HOME}/bin/
vi setDomainEnv.sh
JAVA_HOME=/usr/bin/jdk1.8.0_321

위와같이 설정 변경 후, weblogic을 재기동.

ps -ef|grep java

를 통해 해당 릴리즈 버전으로 정상 기동되었는지 확인하였다.

위 설정 후에도 해당 환경에서는 정상적으로 배포가 되지 않았다.

LIB 검사


application 내 lib속 class의 이상 유무를 검사하였다.

cd lib
# 해당 명령어를 통하여 현재 디렉토리 내부 모든 jar 파일 압축을 해제하였다.
# 해당 명령어를 실행하기 전, lib 디렉토리를 복사 후 실행하자.
for i in `find . -name '*.jar'`; do unzip -qo $i -d $i.delemete; done
# 해당 명령어를 통하여 모든 class 파일의 자바 컴파일 버전을 확인하였다.
find . -name '*.class' |xargs javap -verbose

위 명령어 수행결과, 일부 클래스의 major version이 53임을 확인했다.

  • Java 1.2 uses major version 46
  • Java 1.3 uses major version 47
  • Java 1.4 uses major version 48
  • Java 5 uses major version 49
  • Java 6 uses major version 50
  • Java 7 uses major version 51
  • Java 8 uses major version 52
  • Java 9 uses major version 53

해당 클래스가 포함된 라이브러리(솔루션)의 버전을 낮춘 후 배포하자 정상 작동됨을 확인 할 수 있었다.