diff --git a/gson/pom.xml b/gson/pom.xml index 13c2515a..0063f1cb 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -17,7 +17,7 @@ test - + @@ -56,6 +56,23 @@ org.apache.felix maven-bundle-plugin + + org.codehaus.mojo + templating-maven-plugin + 1.0.0 + + + filtering-java-templates + + filter-sources + + + ${basedir}/src/main/java-templates + ${project.build.directory}/generated-sources/java-templates + + + + diff --git a/gson/src/main/java-templates/com/google/gson/internal/GsonBuildConfig.java b/gson/src/main/java-templates/com/google/gson/internal/GsonBuildConfig.java new file mode 100644 index 00000000..73c61546 --- /dev/null +++ b/gson/src/main/java-templates/com/google/gson/internal/GsonBuildConfig.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 The Gson authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.gson.internal; + +/** + * Build configuration for Gson. This file is automatically populated by + * templating-maven-plugin and .java/.class files are generated for use in Gson. + * + * @author Inderjeet Singh + */ +public final class GsonBuildConfig { + // Based on https://stackoverflow.com/questions/2469922/generate-a-version-java-file-in-maven + + /** This field is automatically populated by Maven when a build is triggered */ + public static final String VERSION = "${project.version}"; +} diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 5b1c6c83..b19302da 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -37,6 +37,7 @@ import java.util.concurrent.atomic.AtomicLongArray; import com.google.gson.internal.ConstructorConstructor; import com.google.gson.internal.Excluder; +import com.google.gson.internal.GsonBuildConfig; import com.google.gson.internal.Primitives; import com.google.gson.internal.Streams; import com.google.gson.internal.bind.ArrayTypeAdapter; @@ -461,7 +462,7 @@ public final class Gson { return candidate; } } - throw new IllegalArgumentException("GSON cannot handle " + type); + throw new IllegalArgumentException("GSON (" + GsonBuildConfig.VERSION + ") cannot handle " + type); } finally { threadCalls.remove(type); @@ -703,6 +704,8 @@ public final class Gson { ((TypeAdapter) adapter).write(writer, src); } catch (IOException e) { throw new JsonIOException(e); + } catch (AssertionError e) { + throw new AssertionError("AssertionError (GSON " + GsonBuildConfig.VERSION + "): " + e.getMessage(), e); } finally { writer.setLenient(oldLenient); writer.setHtmlSafe(oldHtmlSafe); @@ -779,6 +782,8 @@ public final class Gson { Streams.write(jsonElement, writer); } catch (IOException e) { throw new JsonIOException(e); + } catch (AssertionError e) { + throw new AssertionError("AssertionError (GSON " + GsonBuildConfig.VERSION + "): " + e.getMessage(), e); } finally { writer.setLenient(oldLenient); writer.setHtmlSafe(oldHtmlSafe); @@ -935,6 +940,8 @@ public final class Gson { } catch (IOException e) { // TODO(inder): Figure out whether it is indeed right to rethrow this as JsonSyntaxException throw new JsonSyntaxException(e); + } catch (AssertionError e) { + throw new AssertionError("AssertionError (GSON " + GsonBuildConfig.VERSION + "): " + e.getMessage(), e); } finally { reader.setLenient(oldLenient); } diff --git a/gson/src/test/java/com/google/gson/functional/GsonVersionDiagnosticsTest.java b/gson/src/test/java/com/google/gson/functional/GsonVersionDiagnosticsTest.java new file mode 100644 index 00000000..36eff8e1 --- /dev/null +++ b/gson/src/test/java/com/google/gson/functional/GsonVersionDiagnosticsTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2018 Gson Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.gson.functional; + +import java.io.IOException; +import java.util.regex.Pattern; + +import org.junit.Before; +import org.junit.Test; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import junit.framework.TestCase; + +/** + * Functional tests to validate printing of Gson version on AssertionErrors + * + * @author Inderjeet Singh + */ +public class GsonVersionDiagnosticsTest extends TestCase { + private static final Pattern GSON_VERSION_PATTERN = Pattern.compile("(\\(GSON \\d\\.\\d\\.\\d)(?:[-.][A-Z]+)?\\)$"); + + private Gson gson; + + @Before + public void setUp() { + gson = new GsonBuilder().registerTypeAdapter(TestType.class, new TypeAdapter() { + @Override public void write(JsonWriter out, TestType value) { + throw new AssertionError("Expected during serialization"); + } + @Override public TestType read(JsonReader in) throws IOException { + throw new AssertionError("Expected during deserialization"); + } + }).create(); + } + + @Test + public void testVersionPattern() { + assertTrue(GSON_VERSION_PATTERN.matcher("(GSON 2.8.5)").matches()); + assertTrue(GSON_VERSION_PATTERN.matcher("(GSON 2.8.5-SNAPSHOT)").matches()); + } + + @Test + public void testAssertionErrorInSerializationPrintsVersion() { + try { + gson.toJson(new TestType()); + fail(); + } catch (AssertionError expected) { + ensureAssertionErrorPrintsGsonVersion(expected); + } + } + + @Test + public void testAssertionErrorInDeserializationPrintsVersion() { + try { + gson.fromJson("{'a':'abc'}", TestType.class); + fail(); + } catch (AssertionError expected) { + ensureAssertionErrorPrintsGsonVersion(expected); + } + } + + private void ensureAssertionErrorPrintsGsonVersion(AssertionError expected) { + String msg = expected.getMessage(); + // System.err.println(msg); + int start = msg.indexOf("(GSON"); + assertTrue(start > 0); + int end = msg.indexOf("):") + 1; + assertTrue(end > 0 && end > start + 6); + String version = msg.substring(start, end); + // System.err.println(version); + assertTrue(GSON_VERSION_PATTERN.matcher(version).matches()); + } + + private static final class TestType { + @SuppressWarnings("unused") + String a; + } +} diff --git a/gson/src/test/java/com/google/gson/internal/GsonBuildConfigTest.java b/gson/src/test/java/com/google/gson/internal/GsonBuildConfigTest.java new file mode 100644 index 00000000..dc39bc02 --- /dev/null +++ b/gson/src/test/java/com/google/gson/internal/GsonBuildConfigTest.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2018 The Gson authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.gson.internal; + +import static org.junit.Assert.assertFalse; + +import org.junit.Test; + +/** + * Unit tests for {@code GsonBuildConfig} + * + * @author Inderjeet Singh + */ +public class GsonBuildConfigTest { + + @Test + public void testEnsureGsonBuildConfigGetsUpdatedToMavenVersion() { + assertFalse("${project.version}".equals(GsonBuildConfig.VERSION)); + } +}