Programing

Java.lang의 원인.호환되지 않는ClassChangeError?

c10106 2022. 5. 16. 20:19
반응형

Java.lang의 원인.호환되지 않는ClassChangeError?

Java 도서관을 JAR로 포장하고 있는데, 많은 것을 집어던지고 있다.java.lang.IncompatibleClassChangeErrors 그것으로부터 메소드를 호출하려고 할 때.이 오류들은 무작위로 나타나는 것 같다.어떤 종류의 문제들이 이 오류를 일으킬 수 있을까?

이는 클라이언트 코드를 다시 작성하지 않고 라이브러리에 대해 호환되지 않는 일부 이진 변경을 수행했음을 의미한다.자바 언어 규격 §13은 그러한 모든 변화를 가장 두드러지게, 비-비-비-변화를 상세하게 기술하고 있다.static비사적 분야/비사적 분야static또는 그 반대의 경우도 마찬가지야.

새 라이브러리에 대해 클라이언트 코드를 다시 컴파일하십시오. 그러면 바로 가십시오.

업데이트: 공용 라이브러리를 게시하는 경우 "이진 역호환성"이라고 알려진 항목을 보존하기 위해 호환되지 않는 이진 변경을 가능한 한 피해야 한다.종속성 병만 업데이트하는 것이 이상적으로 응용 프로그램이나 빌드를 손상시키지 않아야 한다.이진 역호환성을 깨야 하는 경우에는 변경사항을 해제하기 전에 주 버전 번호(예: 1.x.y에서 2.0.0으로)를 늘리는 것이 좋다.

새로 패키징된 라이브러리는 이전 버전과 역방향 바이너리 호환(BC)이 아님.이러한 이유로 재컴파일되지 않은 라이브러리 클라이언트 중 일부는 예외를 둘 수 있다.

이것은 이전 버전의 라이브러리로 빌드된 클라이언트가 Java.lang을 던지게 할 수 있는 Java 라이브러리 API의 전체 변경 목록이다.비호환성ClassChangeError(예: BC 깨짐):

  1. 최종 필드가 정적이 되면
  2. 일정하지 않은 필드는 정전기적이지 않게 되고,
  3. 클래스가 인터페이스가 됨,
  4. 인터페이스가 클래스가 됨,
  5. 클래스/인터페이스에 새 필드를 추가하는 경우(또는 새 슈퍼클래스/슈퍼인터페이스 추가) 클라이언트 클래스 C의 슈퍼인터페이스에 있는 정적 필드는 C의 슈퍼클래스에서 상속된 추가된 필드(동일한 이름의 필드)를 숨길 수 있다(매우 드문 경우).

참고: 다른 호환되지 않는 변경으로 인해 발생하는 예외는 다음과 같다.NoSuchFieldError, NoSuchMethodError, ImpleAccessError, InstantiationError, VerifyError, NoClassDefoundErrorObstractMethodError.

BC에 대한 더 좋은 논문은 짐 데 리비에르(Jim des Rivier)가 쓴 "Java 기반 APIs 2: API 바이너리 호환성 달성"이다.

또한 그러한 변화를 감지할 수 있는 몇 가지 자동 도구도 있다.

라이브러리에 대한 japi 컴플라이언스 검사기 사용:

japi-compliance-checker OLD.jar NEW.jar

클리러 도구 사용:

java -jar clirr-core-0.6-uber.jar -o OLD.jar -n NEW.jar

행운을 빈다!

이러한 답변들은 모두 맞지만, 문제를 해결하는 것이 더 어려운 경우가 많다.그것은 일반적으로 클래스 경로에 대한 동일한 의존성의 약간 다른 두 버전의 결과물이며, 거의 항상 클래스 경로에 있는 것에 대해 원래 컴파일된 것과 다른 슈퍼클래스나 타동성 폐쇄의 일부 임포트는 다르지만, 클래스 인스턴스화 및 생성자 호출에 있는 것에 의해 발생한다.(클래스 로딩과 ctor 호출에 성공하면NoSuchMethodException아니면 뭐 그런 것)

만약 그 행동이 무작위로 나타난다면, 그것은 아마도 멀티스레드 프로그램이 어떤 코드가 먼저 맞았는지에 따라 다른 타전적 의존성을 분류한 결과일 것이다.

이러한 문제를 해결하려면 다음을 사용하여 VM을 시작해 보십시오.-verbose인수로, 그런 다음 예외가 발생할 때 로드되고 있는 클래스를 보십시오.놀라운 정보를 좀 봐야 한다.예를 들어, 동일한 종속성 및 버전의 복사본이 여러 개 있는 경우, 해당 복사본이 포함되어 있다는 사실을 알고 있었다면 전혀 예상하지 못했거나 수락했을 것이다.

Maven으로 중복된 병을 해결하는 것은 Maven(또는 SBT의 Dependency Graph Plugin) 아래에 있는 maven 의존성 플러그인과 maven-enforcer-plugin의 조합으로 가장 잘 해결되며, 그런 병을 최상위 POM의 한 섹션에 추가하거나 SBT에서 가져온 의존성 요소로 추가하는 것이 좋다.

행운을 빈다!

나는 또한 JNI를 사용할 때, C++에서 Java 메서드를 호출할 때, 호출된 Java 메서드에 파라미터를 잘못된 순서로 전달하면, 호출된 메서드 내의 파라미터를 사용하려고 할 때(타입이 아니기 때문에) 이 오류가 발생한다는 것을 발견했다.처음에 나는 JNI가 당신이 방법을 호출할 때 수업 시그너처 확인의 일환으로 당신을 위해 이런 검사를 하지 않는다는 것에 당황했다. 하지만 나는 그들이 이런 종류의 검사를 하지 않는다고 생각한다. 왜냐하면 당신이 다형성 파라미터를 통과하고 있을 수 있고 그들은 당신이 무엇을 하고 있는지 알고 있다고 가정해야 하기 때문이다.

C++ JNI 코드 예:

void invokeFooDoSomething() {
    jobject javaFred = FredFactory::getFred(); // Get a Fred jobject
    jobject javaFoo = FooFactory::getFoo(); // Get a Foo jobject
    jobject javaBar = FooFactory::getBar(); // Get a Bar jobject
    jmethodID methodID = getDoSomethingMethodId() // Get the JNI Method ID


    jniEnv->CallVoidMethod(javaFoo,
                           methodID,
                           javaFred, // Woops!  I switched the Fred and Bar parameters!
                           javaBar);

    // << Insert error handling code here to discover the JNI Exception >>
    //  ... This is where the IncompatibleClassChangeError will show up.
}

Java 코드 예:

class Bar { ... }

class Fred {
    public int size() { ... }
} 

class Foo {
    public void doSomething(Fred aFred, Bar anotherObject) {
        if (name.size() > 0) { // Will throw a cryptic java.lang.IncompatibleClassChangeError
            // Do some stuff...
        }
    }
}

나도 같은 문제가 있었는데 나중에 알고 보니 6번 버전에서 애플리케이션을 컴파일하는 동안 자바 버전 1.4에서 애플리케이션을 실행하고 있었다.

사실, 그 이유는 중복된 라이브러리를 가지고 있기 때문인데, 하나는 클래스 경로 내에 있고 다른 하나는 클래스 경로 내에 있는 항아리 파일에 포함되어 있다.

나의 경우, 내가 에러를 추가했을 때 에러가 나타났다.com.nimbusds배포된 애플리케이션의 라이브러리Websphere 8.5.
다음과 같은 예외가 발생했다.

원인: java.lang.호환되지 않는 ClassChangeError: org.objectweb.asm.주석 방문기

해결책은 asm 항아리를 도서관에서 제외하는 것이었다.

<dependency>
    <groupId>com.nimbusds</groupId>
    <artifactId>nimbus-jose-jwt</artifactId>
    <version>5.1</version>
    <exclusions>
        <exclusion>
            <artifactId>asm</artifactId>
            <groupId>org.ow2.asm</groupId>
        </exclusion>
    </exclusions>
</dependency>

이 오류가 나타날 수 있는 또 다른 상황은 Emma Code Coverage이다.

이것은 인터페이스에 객체를 할당할 때 발생한다.내 생각에 이것은 더 이상 이진 호환이 되지 않고 계측되는 오브젝트와 관련이 있는 것 같아.

http://sourceforge.net/tracker/?func=auth&aid=3178921&group_id=1969&atid=883351

다행히 이 문제는 코베르투라에게 발생하지 않아서 나는 내 pom.xml의 보고 플러그인에 코베르투라-메이븐-플러그인을 추가했다.

나는 유리물고기와의 전쟁을 철회하고 재배치하는 동안 이 문제에 직면해 왔다.우리 반 구조는 이렇지만

public interface A{
}

public class AImpl implements A{
}

그리고 로 바뀌었다.

public abstract class A{
}

public class AImpl extends A{
}

도메인을 중지하고 다시 시작한 후, 잘 해결되었다.나는 유리피쉬 3.1.43을 사용하고 있었다.

나는 내 로컬 컴퓨터의 Tomcat(8.0.20)에 완벽하게 배포되는 웹 애플리케이션을 가지고 있다.그러나 qa 환경(tomcat - 8.0.20)에 넣었을 때, 비호환 클래스 변경 오류를 계속 주었고 인터페이스로 확장하고 있다는 불만이었습니다.이 인터페이스는 추상 클래스로 변경되었다.그리고 부모와 자식 수업을 취합했는데도 계속 똑같은 문제가 생겼어.마지막으로 디버깅을 하고 싶어서 부모님의 버전을 x.0.1-SNAPSHOT로 변경하고 모든 것을 취합해 현재 작동하고 있다.여기에 제시된 답변을 따르고도 문제가 해결되지 않는 경우, pom.xml의 버전도 올바른지 확인하십시오.버전을 변경하여 작동하는지 확인하십시오.그렇다면 버전 문제를 해결하십시오.

내 대답은 인텔리즈 특유의 것이 될 것이다.

나는 심지어 수동으로 "out"과 "target" dirs를 삭제하기까지 하면서 깨끗하게 재건했다.Intellij는 "유효하지 않은 캐시 및 재시작"을 가지고 있는데, 이것은 때때로 홀수 오류를 삭제한다.이번에는 효과가 없었다.프로젝트 설정->모듈 메뉴에서 종속성 버전이 모두 올바르게 보였다.

최종 답은 내 로컬 면도기에서 내 문제 의존성을 수동으로 삭제하는 것이었다.옛날 버전의 바운시캐슬이 범인이었다(나는 내가 방금 버전을 바꿨고 그것이 문제일 것이라는 것을 알고 있었다) 그리고 비록 구본이 건설되고 있는 곳에서는 아무데도 나타나지 않았지만, 그것은 나의 문제를 해결했다.나는 인텔리전스 버전 14를 사용하다가 이 과정에서 15로 업그레이드했다.

내 경우 이런 식으로 이런 과오를 만났다. pom.xml두 개의 종속성을 정의한 내 프로젝트의A그리고B그리고 둘 다A그리고B동일한 아티팩트에 대해 정의된 종속성(호출)C) 그러나 다른 버전의 (C.1그리고C.2. 이렇게 되면 의 각 클래스에 대해Cmaven은 uber-jar를 구축하는 동안 두 버전에서 클래스 버전을 하나만 선택할 수 있다.종속성 조정 규칙에 따라 '가장 필요한' 버전을 선택하고 '중복 클래스가 있다'는 경고를 출력할 예정이다." 버전 간에 메서드/클래스 시그니처가 변경될 경우java.lang.IncompatibleClassChangeError런타임에 잘못된 버전이 사용된 경우 예외.

고급:만약A의 v1을 사용해야 함C그리고B의 v2를 사용해야 한다.C그러면 우리는 이전을 해야 한다. CA그리고B양쪽 모두에 의존하는 최종 프로젝트를 구축할 때 의 클래스 충돌을 피하기 위한 pums(중복 클래스 경고가 있음)A그리고B.

코드가 클래스 이름과 패키지 정의가 동일한 두 개의 모듈 프로젝트로 구성되어 있지 않은지 확인하십시오.예를 들어, 누군가가 복사-붙여넣기를 사용하여 이전 구현에 기반한 인터페이스의 새로운 구현을 만들 경우 이러한 현상이 발생할 수 있다.

이 오류가 발생할 수 있는 발생 가능성에 대한 기록인 경우:

BeanInstantation이 있는 스프링(3.1.1_release) 구성의 CXF(2.6.0) 로딩 중에 WAS(8.5.0.1)에서 이 오류를 수신함CXF 확장을 롤업한 예외예외, 호환되지 않는 ClassChangeError 롤업.다음 코드 조각은 스택 추적의 요지를 보여준다.

Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.apache.cxf.bus.spring.SpringBus]: Constructor threw exception; nested exception is org.apache.cxf.bus.extension.ExtensionException
            at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:162)
            at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:76)
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:990)
            ... 116 more
Caused by: org.apache.cxf.bus.extension.ExtensionException
            at org.apache.cxf.bus.extension.Extension.tryClass(Extension.java:167)
            at org.apache.cxf.bus.extension.Extension.getClassObject(Extension.java:179)
            at org.apache.cxf.bus.extension.ExtensionManagerImpl.activateAllByType(ExtensionManagerImpl.java:138)
            at org.apache.cxf.bus.extension.ExtensionManagerBus.<init>(ExtensionManagerBus.java:131)
            [etc...]
            at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:147)
            ... 118 more

Caused by: java.lang.IncompatibleClassChangeError: 
org.apache.neethi.AssertionBuilderFactory
            at java.lang.ClassLoader.defineClassImpl(Native Method)
            at java.lang.ClassLoader.defineClass(ClassLoader.java:284)
            [etc...]
            at com.ibm.ws.classloader.CompoundClassLoader.loadClass(CompoundClassLoader.java:586)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:658)
            at org.apache.cxf.bus.extension.Extension.tryClass(Extension.java:163)
            ... 128 more

In this case, the solution was to change the classpath order of the module in my war file. That is, open up the war application in the WAS console under and select the client module(s). In the module configuration, set the class-loading to be "parent last".

This is found in the WAS console:

  • Applicatoins -> Application Types -> WebSphere Enterprise Applications
  • Click link representing your application (war)
  • Click "Manage Modules" under "Modules" section
  • Click link for the underlying module(s)
  • Change "Class loader order" to be "(parent last)".

Documenting another scenario after burning way too much time.

Make sure you don't have a dependency jar that has a class with an EJB annotation on it.

We had a common jar file that had an @local annotation. That class was later moved out of that common project and into our main ejb jar project. Our ejb jar and our common jar are both bundled within an ear. The version of our common jar dependency was not updated. Thus 2 classes trying to be something with incompatible changes.

All of the above - for whatever reason I was doing some big refactor and starting to get this. I renamed the package my interface was in and that cleared it. Hope that helps.

For some reason the same exception is also thrown when using JNI and passing the jclass argument instead of the jobject when calling a Call*Method().

This is similar to the answer from Ogre Psalm33.

void example(JNIEnv *env, jobject inJavaList) {
    jclass class_List = env->FindClass("java/util/List");

    jmethodID method_size = env->GetMethodID(class_List, "size", "()I");
    long size = env->CallIntMethod(class_List, method_size); // should be passing 'inJavaList' instead of 'class_List'

    std::cout << "LIST SIZE " << size << std::endl;
}

I know it is a bit late to answer this question 5 years after being asked but this is one of the top hits when searching for java.lang.IncompatibleClassChangeError so I wanted to document this special case.

Adding my 2 cents .If you are using scala and sbt and scala-logging as dependency ;then this can happen because scala-logging's earlier version had the name scala-logging-api.So;essentially the dependency resolutions do not happen because of different names leading to runtime errors while launching the scala application.

An additional cause of this issue, is if you have Instant Run enabled for Android Studio.

The fix

If you find you start getting this error, turn off Instant Run.

  1. Android Studio main settings
  2. 구축, 실행, 배포
  3. 즉석 실행
  4. "즉시 실행 활성화...."

Instant Run실행 중인 앱에 대한 업데이트를 더 빨리 제공하기 위해 개발 중에 많은 항목을 수정한다.즉석에서 달려간다.그것이 효과가 있을 때, 그것은 정말 유용하다.하지만 이런 문제가 터지면 끄는 게 최선이다.Instant Run다음 버전의 Android Studio가 출시될 때까지.

나는 어떤 인터페이스를 구현하기로 약속하는 추상적인 기본 클래스가 있었기 때문에 이 오류를 얻었지만, 인터페이스 방법의 구현을 추가하는 것을 잊어버렸으며, 그 다음에도 그러한 방법에 대한 구현을 제공하지 않고 추상 클래스를 확장하는 비추상적(구체적) 바이트 코드 생성 클래스를 만들었다.

내가 바이트코드 생성 클래스를 만들려고 했을 때 JVM은java.lang.IncompatibleClassChangeError.

다행히도, 이 예외는 무엇이 잘못되었는지에 대한 더 자세한 정보를 제공하는 "메시지" 멤버를 가지고 있다.필자의 경우 메세지에는 특정 클래스가 특정 인터페이스를 구현하도록 되어 있다고 분명히 적혀 있었지만, 실제로 구현하지는 않았다.

참조URL: https://stackoverflow.com/questions/1980452/what-causes-java-lang-incompatibleclasschangeerror

반응형