revelc/formatter-maven-plugin

lineEnding=KEEP breaks JSON validation on Windows

Closed this issue · 6 comments

dmak commented

test.zip
Describe the bug
A clear and concise description of what the bug is.

Versions (OS, Maven, Java, and others, as appropriate):

  • Affected version(s) of this project: 2.23.0
  • OS: Window 10 x64
  • Maven: 3.9.4
  • Java 17 (OpenJDK build 17+35-2724)

To Reproduce

When I run mvn formatter:validate on the attached project I get the following error:

[INFO] --- formatter:2.23.0:validate (default-cli) @ test ---
[WARNING] 
com.fasterxml.jackson.databind.JsonMappingException: Cannot invoke "String.length()" because "text" is null (through reference chain: java.util.LinkedHashMap["properties"])
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath (JsonMappingException.java:402)
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath (JsonMappingException.java:361)
    at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow (StdSerializer.java:323)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFields (MapSerializer.java:811)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeWithoutTypeInfo (MapSerializer.java:764)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize (MapSerializer.java:720)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize (MapSerializer.java:35)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize (DefaultSerializerProvider.java:479)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue (DefaultSerializerProvider.java:318)
    at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize (ObjectWriter.java:1572)
    at com.fasterxml.jackson.databind.ObjectWriter._writeValueAndClose (ObjectWriter.java:1273)
    at com.fasterxml.jackson.databind.ObjectWriter.writeValueAsString (ObjectWriter.java:1140)
    at net.revelc.code.formatter.json.JsonFormatter.doFormat (JsonFormatter.java:84)
    at net.revelc.code.formatter.AbstractCacheableFormatter.formatFile (AbstractCacheableFormatter.java:83)
    at net.revelc.code.formatter.FormatterMojo.doFormatFile (FormatterMojo.java:776)
    at net.revelc.code.formatter.ValidateMojo.doFormatFile (ValidateMojo.java:74)
    at net.revelc.code.formatter.FormatterMojo.formatFile (FormatterMojo.java:694)
    at net.revelc.code.formatter.FormatterMojo.execute (FormatterMojo.java:469)
    at net.revelc.code.formatter.ValidateMojo.execute (ValidateMojo.java:67)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:126)
    at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute2 (MojoExecutor.java:328)
    at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute (MojoExecutor.java:316)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:212)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:174)
    at org.apache.maven.lifecycle.internal.MojoExecutor.access$000 (MojoExecutor.java:75)
    at org.apache.maven.lifecycle.internal.MojoExecutor$1.run (MojoExecutor.java:162)
    at org.apache.maven.plugin.DefaultMojosExecutionStrategy.execute (DefaultMojosExecutionStrategy.java:39)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:159)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:105)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:73)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:53)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:118)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:261)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:173)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:101)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:906)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:283)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:206)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:77)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:568)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:283)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:226)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:407)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:348)
Caused by: java.lang.NullPointerException: Cannot invoke "String.length()" because "text" is null
    at com.fasterxml.jackson.core.json.WriterBasedJsonGenerator.writeRaw (WriterBasedJsonGenerator.java:554)
    at com.fasterxml.jackson.core.util.DefaultIndenter.writeIndentation (DefaultIndenter.java:90)
    at com.fasterxml.jackson.core.util.DefaultPrettyPrinter.beforeObjectEntries (DefaultPrettyPrinter.java:303)
    at com.fasterxml.jackson.core.json.WriterBasedJsonGenerator._writePPFieldName (WriterBasedJsonGenerator.java:371)
    at com.fasterxml.jackson.core.json.WriterBasedJsonGenerator._writeFieldName (WriterBasedJsonGenerator.java:172)
    at com.fasterxml.jackson.core.json.WriterBasedJsonGenerator.writeFieldName (WriterBasedJsonGenerator.java:155)
    at com.fasterxml.jackson.databind.ser.std.StdKeySerializers$StringKeySerializer.serialize (StdKeySerializers.java:302)
    at com.fasterxml.jackson.databind.ser.std.StdKeySerializers$Dynamic.serialize (StdKeySerializers.java:264)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFields (MapSerializer.java:797)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeWithoutTypeInfo (MapSerializer.java:764)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize (MapSerializer.java:720)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize (MapSerializer.java:35)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize (DefaultSerializerProvider.java:479)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue (DefaultSerializerProvider.java:318)
    at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize (ObjectWriter.java:1572)
    at com.fasterxml.jackson.databind.ObjectWriter._writeValueAndClose (ObjectWriter.java:1273)
    at com.fasterxml.jackson.databind.ObjectWriter.writeValueAsString (ObjectWriter.java:1140)
    at net.revelc.code.formatter.json.JsonFormatter.doFormat (JsonFormatter.java:84)
    at net.revelc.code.formatter.AbstractCacheableFormatter.formatFile (AbstractCacheableFormatter.java:83)
    at net.revelc.code.formatter.FormatterMojo.doFormatFile (FormatterMojo.java:776)
    at net.revelc.code.formatter.ValidateMojo.doFormatFile (ValidateMojo.java:74)
    at net.revelc.code.formatter.FormatterMojo.formatFile (FormatterMojo.java:694)
    at net.revelc.code.formatter.FormatterMojo.execute (FormatterMojo.java:469)
    at net.revelc.code.formatter.ValidateMojo.execute (ValidateMojo.java:67)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:126)
    at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute2 (MojoExecutor.java:328)
    at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute (MojoExecutor.java:316)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:212)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:174)
    at org.apache.maven.lifecycle.internal.MojoExecutor.access$000 (MojoExecutor.java:75)
    at org.apache.maven.lifecycle.internal.MojoExecutor$1.run (MojoExecutor.java:162)
    at org.apache.maven.plugin.DefaultMojosExecutionStrategy.execute (DefaultMojosExecutionStrategy.java:39)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:159)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:105)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:73)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:53)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:118)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:261)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:173)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:101)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:906)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:283)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:206)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:77)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:568)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:283)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:226)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:407)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:348)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal net.revelc.code.formatter:formatter-maven-plugin:2.23.0:validate (default-cli) on project test: Error formatting 'D:\test\src\main\resources\META-INF\additional-spring-configuration-metadata.json'  -> [Help 1]

When <lineEnding>KEEP</lineEnding> is removed, plugin functions correctly:

[ERROR] Failed to execute goal net.revelc.code.formatter:formatter-maven-plugin:2.23.0:validate (default-cli) on project test: File 'D:\test\src\main\resources\META-INF\additional-spring-configuration-metadata.json' has not been previously formatted. Please format file (for example by invoking `mvn net.revelc.code.formatter:formatter-maven-plugin:2.23.0:format`) and commit before running validation! -> [Help 1]

This looks like it's breaking on Linux, too. I'm not sure why. It seems to be failing before it does anything with the line ending, but passes when it is set to AUTO or LF.

Okay, I found the reason. It's because we're initiating the json formatter with a line ending prior to formatting any files. So, if KEEP is set, the actual line ending for that particular file cannot yet be known. We can either determine the line ending and re-initialize the json formatter again and again for each file, or we can just ignore the line ending until after the file is formatted, then fix it then. I think this bug also affects XML formatting.

@dmak Please check to see if the changes in #830 fix your issue. I am unable to test on Windows.

dmak commented

@dmak Please check to see if the changes in #830 fix your issue. I am unable to test on Windows.

Seems to work fine on Windows. Thanks for the fix!

dmak commented

I observe the following issue: when empty JSON

{ }

is formatted, it results the following string (literally):

{ }null

I observe the following issue: when empty JSON

{ }

is formatted, it results the following string (literally):

{ }null

Does this also happen when there's a newline in the file after the empty JSON? If not, I think it might be the auto-detection doesn't quite work when there is no line endings in the file at all. We could add a workaround for that. If it still happens in that case, though, I'm not sure exactly what's going on. I'd have to dig a bit.