Jackson-databind: Restore jdk 6 compatibility

Created on 19 Jun 2019  Â·  23Comments  Â·  Source: FasterXML/jackson-databind

The wording is a bit confusing, but on the docs and the poms for jackson-core and jackson-databind it's stated that they are supposed to work with jdk 6 (altough jdk 7 is required for build/compile).

From the jackson-databind readme:

## Limitation on Dependencies by Core Components

One additional limitation exists for so-called core components (streaming api, jackson-annotations and jackson-databind): no additional dependencies are allowed beyond:

* Core components may rely on any methods included in the supported JDK
    * Minimum JDK version is 1.6 as of Jackson 2.4 and above (1.5 was baseline with 2.3 and earlier)

From the jackson-databind 2.9.9 pom:

<properties>
 <!--
 With Jackson 2.9 we will require JDK 7 (except for annotations/streaming),
         and new language features (diamond pattern) may be used.
         JDK classes are still loaded dynamically since there isn't much downside
         (small number of types); this allows use on JDK 6 platforms still (including
         Android)

-->
<javac.src.version>1.7</javac.src.version>
<javac.target.version>1.7</javac.target.version>

But at the sime time, the target version is set at jdk 1.7 (see above).

Thus, when updating to jackson-core and jackson-databind 2.9.9 and running in a jdk 6 we get:

java.lang.UnsupportedClassVersionError: com/fasterxml/jackson/databind/ObjectMapper : Unsupported major.minor version 51.0

Could java 6 support be restored? Maybe generating a new artifact with jdk6 classifier if the main branch is to be kept jdk 7+?

The reason for this request is that I'm updating dependencies on a legacy system with restrictions on its max jdk version to jdk6, due to CVEs, and jackson-databind ones are only solved in 3.9.9 (latest version with java 6 target was 2.7.9.5 it seems, with 9 found CVEs)

Thanks!

Most helpful comment

@atomax72 Remind me again which contract are you on? How much do you pay for maintenance? Or have you perhaps contributed something of value (whiney comments not included).

Neither I nor this project owes you anything, literally. If you come here whining and bitching, exit is right over there. Do not let the door hit you in the ass on your way out.

All 23 comments

I wanna see what he says... But shew, I can't believe this was even asked.

In December JDK 8 is officially EOL, never mind JDK6. You're asking for CVE security updates, but your JDK has more security issues and flaws than any library you're going to plug into it.

I wanna see what he says, but I personally think the priorities are way off. If I remember right even the JDK 7 minimum is being removed and going minimum JDK 8, because well, JDK 7 also has a ton of security issues that will never get resolved.

Jackson is not your biggest security concern here, and I think you need to give your project manager bit of a wake up call

image

¯_(ツ)_/¯ corporate requirements...

Not related to this issue, but although most of our base platform is already (IBM, not Oracle or OpenJDK) Java 8, there is a small amount of non-migrated servers that impose the java 6 restriction (even if most software does not run on java 6).

I've been trying to compile locally, and testing with the option to generate the java 6 binaries as a separate jar (with the jdk6 qualifier, as maven suggests as an option for cross jdk requirements), is it ok to submit a pull request with those changes so it maybe makes it easier to reconsider this? at least for a v2.9.9.1 / v2.10 so java 6/7 support can be dropped officially on v3...

BTW, thanks for the quick reply!!!

You're definitely incredibly unlucky! :) That is not a nice restriction at all, you're a better man than I am considering I would hand in my resignation the instant the request was forced upon me.

The owner of this one is @cowtowncoder - this is 100% his decision.

JDK 13 still compiles to JDK6, so other than 'this shouldn't be done under any circumstances', there isn't really a reason why not (LOL)- aside from not being able to use typed generics and everything else. The suite of dependencies and modules/plugins as well is the complexity that you're missing I think. A lot of the addon-modules use language features from JDK 7 and up.

The deploy runs through them all, so they will all need a jdk6 profile, not just the core 3.

@cowtowncoder I can offer to throw this into my suite of moduled offerings to lessen the blow, if he is ok with that, that should help him get on his feet without affecting the global distribution?

I've been through worse... ;-)

I think the 'official' wording in jackson is only core components (-core and -bindings?) support jdk 6. In my case, that is all I need, so maybe this could be restricted to this project. In fact, jackson-core still has target 1.6 as of v2.9.9

Except for a few diamond operators and try-with-resources, most of the code here compiles to jdk 6, and tests may be left untouched, as with the qualifier approach they would compile and run with the jdk7 option...

I've just submitted a PR to 2.10 so you can assess it #2361 (could also be rebased if you think this would fit better for a v2.9.9.1)

Anyways, thanks for all the help, whatever the outcome :-)

Let me double check my "facts", everything changes with time, but from what I recall - specifying source as 1.8 and target as 1.6 should solve all the changes for backwards compatibility without reintroducing performance regressions from code changes - I imagine eclipse still hasn't solved its maven integration so that's probably why you went and changed all the sources.
Let me double check this first though.

To solve the profile does not exist problem for travis, the profile for jdk 6 should be put in the base/bom as well.

First looks show a lot of regressions in the changes, and a PR that is a little too big to approve, But I'm chalking that down to IDE Maven integration as the cause.
Lets see what can happen here.

I've been down the legacy road many times lol :) It's why I won't ever accept it again xD

No, sorry, javac only accepts target level <= source level, so target 1.6 and source 1.7 is a no-go.

About the PR, changes, though there are many are just syntactical, and all of them belong to either of these three cases. All due to syntax only available in java 7, but replicable with the same functionality with java 6 compliant code:

  • Diamond operators, as in:
-        List<CreatorCandidate> nonAnnotated = new LinkedList<>();
+        List<CreatorCandidate> nonAnnotated = new LinkedList<CreatorCandidate>();

These are usually managed automatically by the IDE (Eclipse in my case) as the type arguments are always auto-detectable.

  • Try-with-resources statements as in:
    ```
    protected JsonNode _readTreeAndClose(JsonParser p0) throws IOException
    {
  • try (JsonParser p = p0) {
  • JsonParser p = p0;
  • try {
    final JavaType valueType = JSON_NODE_TYPE;

         DeserializationConfig cfg = getDeserializationConfig();
    

    @@ -4061,6 +4067,10 @@
    // No ObjectIds so can ignore
    // ctxt.checkUnresolvedObjectId();
    return (JsonNode) result;

  • } finally {
  • try {
  • p.close();
  • } catch (IOException ioe) { }
    }
    }
Just done it the old way, with the declaration outside the try block and a finally to close.

* Multi catches as in:
  • } catch (IllegalAccessException | InvocationTargetException e) {
  • } catch (IllegalAccessException e) {
  • throw new IllegalArgumentException(
  • "Failed to setValue() with method " + getFullName() + ": " + e.getMessage(), e);
  • } catch (InvocationTargetException e) {
    throw new IllegalArgumentException("Failed to setValue() with method "
    +getFullName()+": "+e.getMessage(), e);
    }
    ```

Just separate the two exceptions, each with its own (copied) block

From the note at the bottom of the compiler-plugin page:

Merely setting the target option does not guarantee that your code actually runs on a JRE with the specified version. The pitfall is unintended usage of APIs that only exist in later JREs which would make your code fail at runtime with a linkage error. To avoid this issue, you can either configure the compiler's boot classpath to match the target JRE or use the Animal Sniffer Maven Plugin to verify your code doesn't use unintended APIs

It will compile and run in the lower target, but there is no guarantee that it won't break when it hits the affected code.
The changes you've made won't beak compiling down to a lower version as it's just a change in the generic typecasting.

This is pretty much what I remember about compiling to a lower version.

Oh as well, moving from try-with-resources is not just as simple as expanding it back to a finally clause as there are operations occurring in the finalize() of the generated structure try() that no longer will run with it expanded, hence, it is a regression.
Try-With-Resources is not just a sugar-syntax, expanding it out is a performance regression and removes one of the resolutions to memory management within a try-catch block. This will re-introduce previous issues.

Shew dude.

Actually.
I'm out.

Sort it out with @cowtowncoder

Thanks for the feedback and the comments @GedMarc . Didn't knew about the memory optimizations on the try-with-resources, but will look into it! :-)

Will wait for @cowtowncoder to decide on this, then.

Meanwhile, I've submitted another option for a PR, #2364 . Should it be accepted instead for a 2.9.9.1. On this one I've just reverted source and target to 1.6 directly (as I saw the classifier option was not really working as intended). Refactored tests as well here, and most pass, but I have 3 failures that seem OS and timezone dependant.

Sorry if I'm too verbose, I'll be out for some days with no access to the internet and wanted to leave my point here.

BTW, I'm not the only one... Someone appeared on a depending project with simmilar issues: https://github.com/intuit/QuickBooks-V3-Java-SDK/issues/51

Thanks and greetings!

So. I think I mentioned this on mailing list, but the problems are manifold, including javac inability (with later versions) to produce, say, Java 6 bytecode with source settings beyond 1.6 (at least with JDK 8). Worse, attempting to do this with via Maven as part of release process will not work well (Sonatype OSS repository requires things that only work with stock JDK 8 -- there may be a complicated way to get JDK 7 to work, but I wasn't able to figure that out last time I tried releasing Jackson with JDK 7 (I wish I had link handy now to article by Sonatype that explains this).

So JDK 7 is the baseline for 2.9, aside from jackson-core (streaming) and jackson-annotations which should still build for Java 6.

I think more likely approach for those needing Java 6 runtime is to use a tool like:

https://github.com/luontola/retrolambda

possibly first verifying there are no unprotected calls to JDK 6+ classes using something like

https://www.mojohaus.org/animal-sniffer/

(but note that there are couple of dynamically loaded pieces that do refer to JDK 7 -- these will not prevent code from running on JDK 6 as class loading failure is handled dynamically).

Maybe it would be best to go with something that google does for Guava which is having a different version ending such as -andriod version which is jdk 1.7 compatible. (tho in this case 1.6 which Android did support before 2014? and it seems it can only use 1.6 api's but can compile with 1.7 and turn in 1.6 systems ...)
https://github.com/google/guava
https://stackoverflow.com/questions/20480090/does-android-support-jdk-6-or-7

At this point I do not have time, resources or necessarily interest to work on this, so if anyone wants to build support, it probably makes sense to create separate github project(s) for repackaging, publishing.

I can help in documenting existing pieces wrt where compatibility actually fails, for standard jackson components.

Sorry for not getting back, I was a few days out on holidays :-)

We've been doing some tests lately and have locally built a version that works correctly for jdk 6 (using oracle jdk 8 with source and target to 1.6) and will be using this internally. I have no experience in the use of retrolambda and the like so it was simpler for us to adjust the code. I've updated the merge request (it was missing removal of two uses of Collections.emptyIterator()). It'd be great if this was uploaded with the original jackson databind or at least using a jdk6 classifier (as maven suggests here). Else I'll just leave the code there should anyone need to compile it themselves.

Feel free to ask if I can be of any help!

Thanks and greetings!

BTW, the readme for the project should be updated anyway, as it still states java 6 runtime compatibility for core components, and includes this one (and nowadays it's not the case)!

Hi @mediocaballero,

After looking at guava, it seems they just copy the entire jre folder to the android folder and it's treated as a separate but similar fork. This is not very fun to support for something that was not needing to deal with this (aka guava is majorly used by andriod phones).

I've created a PR to your repo on a way to have jdk1.6 co-live with 1.8 without affecting the normal code base. You can find it here https://github.com/mediocaballero/jackson-databind/pull/1 and the main work in commit https://github.com/mediocaballero/jackson-databind/pull/1/commits/9dcfeeb6902e0c7b7f523032c1a52dcdc5751660 (please note that it does not compile-pass with 1.6 yet as did not fix all files and your singular commit does not seem to be on a branch??? so cherry pick the pom changes and copy your tweaked files to the java6 folder and revert the base files)

What this does is similar to the maven war plugin (overlay feature) which is to exclude certain java files which we can't compile with and put in our own. Yes there is a little more work to keep it in sync with the version going forward but it does give the ability to be at 1.6 without affecting cowtowncoder and co's need to support 1.8 LTS and jdk 11 LTS + which people are now moving towards.

Hope this helps.

Regards,

@duttonw

going with your first pull request, i've done the split, does compile with the -P jdk16 flag to make 1.6 source/target using jdk8. https://github.com/duttonw/jackson-databind/tree/%232360

It is a lot messier than I was expecting.

Hi @mediocaballero ,

With your merge of mediocaballero#1 and usage of a personal nexus (or similar product ahem https://github.com/features/package-registry)

Do you still require this functionality placed back into the main project?

I'm of the opinion that the project needs to support current gen java and that the documentation now needs to be updated to reflect this. (i.e. no)

You now have a way to take the latest version of databind and drop out certain files with their 1.6 compatible version and the use of a classifier to note that. Your management should now be happy to have the latest (non-cve) version of databind for this yet to be upgrade piece of tech you need to support.

And as such this ticket could be resolved.

If others require 1.6 support then they can look at the pull requests/commits on this ticket to get a general idea of how its done. Or use your fork to build their own version in their private repo.

Hope this has been useful to the community and to your endeavours @mediocaballero and good luck on getting all of your app's to at least 1.7 but hopefully 1.8+,

Regards,

@duttonw

Hi! First of all, thanks for all your help and support, and for the work on the PR, its great!!!

Sorry for late reply... I was on holiday and then trying to catch up on pending work. I've still not been able to test this locally or add the patched files from my fork, but I got the general idea: for jdk6 I should use the jdk6 profile, that will generate a jdk6-classified jar, and, in the source jdk6 folder, I should place ony the files that need changes to be jdk6-compatible, right?

I still think this would be great if included in the main project, at least for version 2, as there might be some people in the same situation and jackson-databind is a very widely used library (some questions arised from a depending project in a simmilar situation)... I totally agree as well with the need to move forward for version 3 and forget older jdks there...

Thanks again for all your help!

Sounds like there could be a solution that does not require main jackson-databind to change.
I will go ahead and update README to correctly indicate that 2.7.x was the latest version to have bytecode at JDK 6 compatible level.

so stupid answers the question is real
we are programmers that work very often with client's software
this software can be very old for example 10 or more years
for example made in JDK1.6
try force a client to understand he must change JDK version on his software
I worked in Telecom, Enel, INPS, INPDAP, Ministry and other public administaration and they always have old software developed with old java version
so we need compliant libraries instead of changing product because is not still supporting our JDK version!

@atomax72 Remind me again which contract are you on? How much do you pay for maintenance? Or have you perhaps contributed something of value (whiney comments not included).

Neither I nor this project owes you anything, literally. If you come here whining and bitching, exit is right over there. Do not let the door hit you in the ass on your way out.

See: https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.12

-+ Tatu +-

On Wed, May 5, 2021 at 11:15 PM PrincyMichael @.*>
wrote:

Is the new update 2.12 compatible with JDK 1.6

—
You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub
https://github.com/FasterXML/jackson-databind/issues/2360#issuecomment-833257098,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAANOGKVNB5Z5KHJXSDJY6TTMIXZPANCNFSM4HZIH4PA
.

Was this page helpful?
0 / 5 - 0 ratings