FasterXML / FasterXML/jackson-modules-base

Afterburner class generation isn't compatible with PowerMock >=1.7.0, causing class cast exceptions

オープン
#53 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る
afterburner
主要言語
Java
スター
180
フォーク
80
平均マージ
3時間 26分
マージ済み PR(30日)
1

説明

Doing powermock tests with Afterburner optimization are causing "cannot cast" exceptions for both mutator and accessor generated classes.

This happens because when afterburner is creating the methods, it is by mistaken returning an incompatible class from a upper classloader, which isn't compatible.

This happens at [`generateAccessorClass`](https://github.com/FasterXML/jackson-modules-base/blob/178e14b4cf8b6e57692661e299b1a3df7e092874/afterburner/src/main/java/com/fasterxml/jackson/module/afterburner/ser/PropertyAccessorCollector.java#L170) function,
In old powermock versions when a class was not found, it used to [throw](https://github.com/powermock/powermock/commit/a78afc5ffc0bc031d46d7aae41f15b4e830522b8#diff-fe596ed12260c210e636b956c2532decL244) a `ClassNotFoundException`, but now it is [returning](https://github.com/powermock/powermock/blob/4f34a0899446e0a7f5fa5f6f336aa4ab388461ea/powermock-core/src/main/java/org/powermock/core/classloader/MockClassLoader.java#L256) (correctly?) the class if it exists in the system class loader. This also [happens](https://github.com/powermock/powermock/blob/release/2.x/powermock-core/src/main/java/org/powermock/core/classloader/javassist/JavassistMockClassLoader.java#L86) in powermock 2.x branch.

I'm not 100% sure the problem is only at fasterxml afterburner code, powermock could be partially mistaken as well.

But, I think the way to solve this bug correctly in Afterburner is to make sure in [`PropertyAccessorCollector`](https://github.com/FasterXML/jackson-modules-base/blob/178e14b4cf8b6e57692661e299b1a3df7e092874/afterburner/src/main/java/com/fasterxml/jackson/module/afterburner/ser/PropertyAccessorCollector.java#L170) and [`PropertyMutatorCollector`](https://github.com/FasterXML/jackson-modules-base/blob/178e14b4cf8b6e57692661e299b1a3df7e092874/afterburner/src/main/java/com/fasterxml/jackson/module/afterburner/deser/PropertyMutatorCollector.java#L179) that the class which is returned by `classLoader.loadClass` is indeed compatible with its matching class interface (`BeanPropertyAccessor` or `BeanPropertyMutator.class`), and if not to generate it as usual ([`classLoader.loadAndResolve`](https://github.com/FasterXML/jackson-modules-base/blob/178e14b4cf8b6e57692661e299b1a3df7e092874/afterburner/src/main/java/com/fasterxml/jackson/module/afterburner/ser/PropertyAccessorCollector.java#L173))

The current situation makes fasterxml+afterburner+powermock above 1.7.0 to fail when your project have some of tests with powermock and some without.
The only way to mitigate it is either disable afterburner, or make sure all unit-tests run in separate jvms (slows down the unit-tests)

And since all powermock 2.x releases has this incompatibility as well, it means there's no Java11 compatible version of powermock which could run those unit-tests without the mitigations above.

attached unit-test to show the failure, it will first execute `Test1` which will create the afterburner accessors at the system class loader, and then `Test2` (with powermock/`MockClassLoader`) will throw that cast exception.
```
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner;

import java.io.IOException;

@RunWith(Enclosed.class)
public class TestFailure {
private static class MyObject {
@JsonProperty("object")
public String object;
};

private static void doit() throws IOException {
ObjectMapper objectMapper =
new ObjectMapper();

// causes the exception of:
// java.lang.IllegalStateException: Failed to generate accessor class 'TestFailure$MyObject$Access4JacksonSerializerac50bfc2': TestFailure$MyObject$Access4JacksonSerializerac50bfc2 cannot be cast to com.fasterxml.jackson.module.afterburner.ser.BeanPropertyAccessor
objectMapper.registerModule(new AfterburnerModule());

MyObject o = new MyObject();
objectMapper.readValue(objectMapper.writeValueAsString(o), MyObject.class);
}

@RunWith(PowerMockRunner.class)
public static class Test2 {
@Test
public void testWithPowerMock() throws IOException {
doit();
}
}

public static class Test1 {
@Test
public void testWithoutPowerMock() throws IOException {
doit();
}
}
}
```

pom (changing powermock version to `1.7.0RC4` solves it, as they fixed a bug and caused this regression in [this commit](https://github.com/powermock/powermock/commit/a78afc5ffc0bc031d46d7aae41f15b4e830522b8#diff-fe596ed12260c210e636b956c2532decL244)):
```

4.0.0

testfailure
testfailure
1.0-SNAPSHOT


1.8
1.8
1.7.0
2.9.6



org.powermock
powermock-module-junit4
${powermock.version}
test


org.powermock
powermock-api-mockito
${powermock.version}
test


junit
junit
4.12


com.fasterxml.jackson.core
jackson-annotations
${fasterxml.jackson.version}


com.fasterxml.jackson.module
jackson-module-afterburner
${fasterxml.jackson.version}


com.fasterxml.jackson.module
jackson-module-jaxb-annotations
${fasterxml.jackson.version}


com.fasterxml.jackson.core
jackson-databind
${fasterxml.jackson.version}


com.fasterxml.jackson.core
jackson-core
${fasterxml.jackson.version}


com.sun.activation
javax.activation
1.2.0

```

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

評価

この issue はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。