FasterXML / FasterXML/jackson-modules-base

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

Ouverte
#53 1 commentaire 0 réactions 0 personnes assignées Voir sur GitHub
afterburner
Langage dominant
Java
Étoiles
180
Forks
80
Merge moyen
3 h 26 min
PR mergées (30 j)
1

Description

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

```

Guide de contribution

Aucun guide de contribution indexé pour ce dépôt

Évaluation

Cette issue n'a pas encore été évaluée.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.