Order of Manifest Attributes is no longer preserved

Gradle Version: 2.14
Operating System: Windows 7
Is this a regression? If yes, which version of Gradle do you know it last worked for?
Yes, last working in 2.13.

Since Gradle 2.14 the order of manifest attributes is no longer preserved.
My guess is that at some point a HashMap is used instead of a LinkedHashMap, but I am not certain.
The following build file creates a correct manifest in 2.13, but mixes the attributes in 2.14.

apply plugin: 'java'

task wrapper(type: Wrapper) {
  gradleVersion = '2.14'
}

jar {
  manifest.attributes (
    'm':'d',
    'a':'b',
    'n':'f',
    'i':'2',
    'f':'g',
    'e':'5',
    's':'f',
    't':'9'
    )
}

Manifest in 2.13 (keys can be read as ‘manifest’):

Manifest-Version: 1.0
m: d
a: b
n: f
i: 2
f: g
e: 5
s: f
t: 9

Manifest in 2.14:

Manifest-Version: 1.0
a: b
s: f
t: 9
e: 5
f: g
i: 2
m: d
n: f
1 Like

Thanks for the report Adrian!

Starting with 2.14, Gradle uses java.util.jar.Manifest to handle manifests instead of the manifest implementation from Ant.
This change was needed to fix manifest encoding issues as part of GRADLE-3374.

And you’re right, java.util.jar.Manifest uses HashMaps internally.
We can’t do much about this.

There’s no order contract in the Manifest specification.
What are you trying to achieve that depends on the order of attributes in the written manifest?

That is unfortunate, I have tests that assert that the Manifest of our applications are generated correctly (date, Revision, specification Version, …). To do this I just asserted that the Manifest Text was as expected, but now the entries are mixed up. I guess I will have to parse the Manifest or I could loop over the expected entries and assert that they are contained.

Yes. One way to to it is to use java.util.jar.Manifest to parse the manifest, that way you assert that the JVM will properly load the generated manifests, e.g.:

File manifestFile = ...
try(InputStream input = new FileInputStream(manifestFile)) {
  Manifest manifest = new Manifest(input);
  // And use manifest.getMainAttributes() and manifest.getEntries()
  // to assert on main attributes and sections
}

HTH

Thanks for the hint, that is the way I am going to go :smiley:

1 Like