diff --git a/README.md b/README.md index 7a64aae8d..6a2094450 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ in less than one second and therewith can be easily integrated in each build. * Comparison of two jar archives without the need to add all of their dependencies to the classpath. * Differences are printed on the command line in a simple diff format. -* Differences can optionally be printed as XML or HTML file. +* Differences can optionally be printed as [Markdown](https://www.markdownguide.org/), XML or HTML file. * Per default private and package protected classes and class members are not compared. If necessary, the access modifier of the classes and class members to be compared can be set to public, protected, package or private. * Per default all classes are tracked. If necessary, certain packages, classes, methods or fields can be excluded or explicitly included. Inclusion and exclusion is also possible based on annotations. diff --git a/doc/japicmp_guava.md b/doc/japicmp_guava.md new file mode 100644 index 000000000..ec876f46d --- /dev/null +++ b/doc/japicmp_guava.md @@ -0,0 +1,3177 @@ + +# Compatibility Report + +![semver MAJOR](https://img.shields.io/badge/semver-MAJOR-red?logo=semver "semver MAJOR") + +## Summary + +> [!CAUTION] +> +> Incompatible changes found while checking backward compatibility of version `19.0` with the previous version `18.0`. + +
+Expand to see options used. + +- **Report only summary**: No +- **Report only changes**: Yes +- **Report only binary-incompatible changes**: No +- **Access modifier filter**: `PROTECTED` +- **Old archives**: + - ![guava 18.0](https://img.shields.io/badge/guava-18.0-blue "guava 18.0") +- **New archives**: + - ![guava 19.0](https://img.shields.io/badge/guava-19.0-blue "guava 19.0") +- **Evaluate annotations**: Yes +- **Include synthetic classes and class members**: No +- **Include specific elements**: No +- **Exclude specific elements**: No +- **Ignore all missing classes**: No +- **Ignore specific missing classes**: No +- **Treat changes as errors**: + - Any changes: No + - Binary incompatible changes: No + - Source incompatible changes: No + - Incompatible changes caused by excluded classes: Yes + - Semantically incompatible changes: No + - Semantically incompatible changes, including development versions: No +- **Classpath mode**: `ONE_COMMON_CLASSPATH` +- **Old classpath**: +``` + +``` +- **New classpath**: +``` + +``` + +
+ + +## Results + +| Status | Type | Serialization | Compatibility Changes | +|----------------------------|-----------------------------------------------------------|-------------------------------------|-----------------------| +| Unchanged | [com.google.common.base.Ascii] | ![Not serializable] | ![Annotation added] ![Annotation removed] | +| Unchanged | [com.google.common.base.CaseFormat] | ![Compatible] | ![Annotation added] | +| Modified | [com.google.common.base.CharMatcher] | ![Not serializable] | ![Method added to public class] | +| Unchanged | [com.google.common.base.Defaults] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.base.Enums] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.base.Equivalence] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.base.Functions] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.base.Joiner] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.base.Joiner$MapJoiner] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.base.MoreObjects] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.base.MoreObjects$ToStringHelper] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.base.Objects] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.base.Optional] | ![Compatible] | ![Annotation added] | +| Unchanged | [com.google.common.base.Predicates] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.base.Splitter] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.base.Splitter$MapSplitter] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.base.StandardSystemProperty] | ![Compatible] | ![Annotation added] | +| Unchanged | [com.google.common.base.Stopwatch] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.base.Strings] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.base.Suppliers] | ![Not serializable] | ![Annotation added] | +| Modified | [com.google.common.base.Throwables] | ![Not serializable] | ![Annotation added] ![Method added to public class] | +| Unchanged | [com.google.common.base.Ticker] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.base.Utf8] | ![Not serializable] | ![Annotation added] | +| Modified | [com.google.common.base.VerifyException] | ![Default serialversionuid changed] | ![No changes] | +| Modified | [com.google.common.cache.CacheLoader$UnsupportedLoadingOperationException] | ![Default serialversionuid changed] | ![No changes] | +| Modified | [com.google.common.cache.RemovalNotification] | ![Not serializable] | ![Method added to public class] | +| Unchanged | [com.google.common.collect.BiMap] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.collect.Collections2] | ![Not serializable] | ![Annotation added] | +| Modified | [com.google.common.collect.ComparisonChain] | ![Not serializable] | ![Annotation added] ![Annotation deprecated added] ![Method added to public class] | +| Modified | [com.google.common.collect.FluentIterable] | ![Not serializable] | ![Annotation added] ![Method added to public class] | +| Modified | [com.google.common.collect.HashBiMap] | ![Superclass modified] | ![Superclass added] ![Method return type generics changed] | +| Modified | [com.google.common.collect.ImmutableBiMap] | ![Default serialversionuid changed] | ![Method added to public class] | +| Modified | [com.google.common.collect.ImmutableBiMap$Builder] | ![Not serializable] | ![Method added to public class] | +| Modified | [com.google.common.collect.ImmutableClassToInstanceMap] | ![Default serialversionuid changed] | ![Method added to public class] | +| Modified | [com.google.common.collect.ImmutableCollection] | ![Default serialversionuid changed] | ![Method now abstract] | +| Serialization-incompatible | [com.google.common.collect.ImmutableList] | ![Default serialversionuid changed] | ![No changes] | +| Modified | [com.google.common.collect.ImmutableListMultimap] | ![Compatible] | ![Method added to public class] | +| Modified | [com.google.common.collect.ImmutableListMultimap$Builder] | ![Not serializable] | ![Method added to public class] | +| Modified | [com.google.common.collect.ImmutableMap] | ![Default serialversionuid changed] | ![Method added to public class] | +| Modified | [com.google.common.collect.ImmutableMap$Builder] | ![Not serializable] | ![Method added to public class] | +| Modified | [com.google.common.collect.ImmutableMultimap] | ![Compatible] | ![Method added to public class] | +| Modified | [com.google.common.collect.ImmutableMultimap$Builder] | ![Not serializable] | ![Method added to public class] | +| Modified | [com.google.common.collect.ImmutableMultiset] | ![Default serialversionuid changed] | ![No changes] | +| Modified | [com.google.common.collect.ImmutableRangeMap] | ![Compatible] | ![Interface added] ![Method added to public class] | +| Modified | [com.google.common.collect.ImmutableRangeSet] | ![Default serialversionuid changed] | ![Method added to public class] | +| Modified | [com.google.common.collect.ImmutableSetMultimap] | ![Compatible] | ![Method added to public class] | +| Modified | [com.google.common.collect.ImmutableSetMultimap$Builder] | ![Not serializable] | ![Method added to public class] | +| Modified | [com.google.common.collect.ImmutableSortedMap] | ![Compatible] | ![Class now final] ![Method added to public class] | +| Modified | [com.google.common.collect.ImmutableSortedMap$Builder] | ![Not serializable] | ![Annotation deprecated added] ![Method added to public class] | +| Source-incompatible | [com.google.common.collect.ImmutableSortedMultiset] | ![Compatible] | ![Class generic template generics changed] | +| Serialization-incompatible | [com.google.common.collect.ImmutableSortedSet] | ![Default serialversionuid changed] | ![No changes] | +| Unchanged | [com.google.common.collect.Iterables] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.collect.Iterators] | ![Not serializable] | ![Annotation added] | +| Modified | [com.google.common.collect.Lists] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.collect.MapConstraint] | ![Not serializable] | ![Annotation deprecated added] | +| Unchanged | [com.google.common.collect.MapConstraints] | ![Not serializable] | ![Annotation deprecated added] | +| Modified | [com.google.common.collect.MapMaker] | ![Not serializable] | ![Method less accessible] | +| Modified | [com.google.common.collect.Maps] | ![Not serializable] | ![Annotation added] ![Method added to public class] | +| Unchanged | [com.google.common.collect.MultimapBuilder] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.collect.Multimaps] | ![Not serializable] | ![Annotation added] | +| Modified | [com.google.common.collect.Multisets] | ![Not serializable] | ![Annotation added] ![Method added to public class] | +| Modified | [com.google.common.collect.RangeMap] | ![Not serializable] | ![Method added to interface] | +| Modified | [com.google.common.collect.RangeSet] | ![Not serializable] | ![Method added to interface] | +| Unchanged | [com.google.common.collect.Sets] | ![Not serializable] | ![Annotation added] ![Annotation deprecated added] | +| Unchanged | [com.google.common.collect.Table] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.collect.Table$Cell] | ![Not serializable] | ![Annotation added] | +| Modified | [com.google.common.collect.TreeRangeMap] | ![Not serializable] | ![Method added to public class] | +| Modified | [com.google.common.collect.TreeRangeSet] | ![Not serializable] | ![Method added to public class] | +| Modified | [com.google.common.eventbus.AsyncEventBus] | ![Not serializable] | ![Method removed] | +| Modified | [com.google.common.eventbus.DeadEvent] | ![Not serializable] | ![Method added to public class] | +| Modified | [com.google.common.eventbus.EventBus] | ![Not serializable] | ![Method added to public class] | +| Modified | [com.google.common.hash.BloomFilter] | ![Default serialversionuid changed] | ![Annotation added] ![Method added to public class] | +| Unchanged | [com.google.common.hash.Funnels] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.hash.HashCode] | ![Not serializable] | ![Annotation added] | +| Modified | [com.google.common.hash.Hasher] | ![Not serializable] | ![Annotation added] ![Annotation deprecated added] ![Method added to interface] | +| Modified | [com.google.common.hash.Hashing] | ![Not serializable] | ![Annotation added] ![Method added to public class] | +| Unchanged | [com.google.common.hash.HashingInputStream] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.hash.HashingOutputStream] | ![Not serializable] | ![Annotation added] | +| Modified | [com.google.common.io.BaseEncoding] | ![Not serializable] | ![Method now abstract] | +| Modified | [com.google.common.io.ByteSource] | ![Not serializable] | ![Method added to public class] | +| Modified | [com.google.common.io.CharSource] | ![Not serializable] | ![Method added to public class] | +| Modified | [com.google.common.net.HttpHeaders] | ![Not serializable] | ![No changes] | +| Modified | [com.google.common.net.MediaType] | ![Not serializable] | ![No changes] | +| Unchanged | [com.google.common.primitives.Booleans] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.primitives.Bytes] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.primitives.Chars] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.primitives.Doubles] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.primitives.Floats] | ![Not serializable] | ![Annotation added] | +| Modified | [com.google.common.primitives.Ints] | ![Not serializable] | ![Annotation added] | +| Modified | [com.google.common.primitives.Longs] | ![Not serializable] | ![Annotation added] ![Method added to public class] | +| Unchanged | [com.google.common.primitives.Primitives] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.primitives.Shorts] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.primitives.SignedBytes] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.primitives.UnsignedBytes] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.primitives.UnsignedInteger] | ![Compatible] | ![Annotation added] ![Annotation removed] | +| Unchanged | [com.google.common.primitives.UnsignedInts] | ![Not serializable] | ![Annotation added] | +| Unchanged | [com.google.common.primitives.UnsignedLong] | ![Compatible] | ![Annotation added] | +| Unchanged | [com.google.common.primitives.UnsignedLongs] | ![Not serializable] | ![Annotation added] | +| Modified | [com.google.common.reflect.ClassPath$ResourceInfo] | ![Not serializable] | ![No changes] | +| Modified | [com.google.common.reflect.TypeToken] | ![Default serialversionuid changed] | ![Annotation deprecated added] ![Method added to public class] | +| Modified | [com.google.common.util.concurrent.AbstractFuture] | ![Not serializable] | ![No changes] | +| Modified | [com.google.common.util.concurrent.AbstractListeningExecutorService] | ![Not serializable] | ![Method return type changed] | +| Unchanged | [com.google.common.util.concurrent.FutureFallback] | ![Not serializable] | ![Annotation deprecated added] | +| Modified | [com.google.common.util.concurrent.Futures] | ![Not serializable] | ![Annotation added] ![Annotation deprecated added] ![Superclass added] ![Method added to public class] | +| Modified | [com.google.common.util.concurrent.SettableFuture] | ![Not serializable] | ![Superclass added] ![Method added to public class] | + +
+Expand for details. + +___ + + +### `com.google.common.base.Ascii` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|---------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Ascii` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|----------|------------|-------------------------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | | [`String`] | `truncate`([`CharSequence`], `int`, [`String`]) | ~~[`CheckReturnValue`]~~ | | ![Annotation removed] | + +___ + + +### `com.google.common.base.CaseFormat` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|---------------------|------|--------------|-------------|-------|---------------|-----------------------| +| Unchanged | `public` `abstract` | Enum | `CaseFormat` | [`Enum`] | JDK 6 | ![Compatible] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.base.CharMatcher` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------|-------|---------------|------------|-------|---------------------|-----------------------| +| Modified | `public` `abstract` | Class | `CharMatcher` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|---------------------------|----------|---------------------|----------------------------|-------------|--------|-----------------------| +| Added | **`static`** **`public`** | | **[`CharMatcher`]** | **`any`**() | | | ![Method added to public class] | +| Added | **`static`** **`public`** | | **[`CharMatcher`]** | **`ascii`**() | | | ![Method added to public class] | +| Added | **`static`** **`public`** | | **[`CharMatcher`]** | **`breakingWhitespace`**() | | | ![Method added to public class] | +| Added | **`static`** **`public`** | | **[`CharMatcher`]** | **`digit`**() | | | ![Method added to public class] | +| Added | **`static`** **`public`** | | **[`CharMatcher`]** | **`invisible`**() | | | ![Method added to public class] | +| Added | **`static`** **`public`** | | **[`CharMatcher`]** | **`javaDigit`**() | | | ![Method added to public class] | +| Added | **`static`** **`public`** | | **[`CharMatcher`]** | **`javaIsoControl`**() | | | ![Method added to public class] | +| Added | **`static`** **`public`** | | **[`CharMatcher`]** | **`javaLetter`**() | | | ![Method added to public class] | +| Added | **`static`** **`public`** | | **[`CharMatcher`]** | **`javaLetterOrDigit`**() | | | ![Method added to public class] | +| Added | **`static`** **`public`** | | **[`CharMatcher`]** | **`javaLowerCase`**() | | | ![Method added to public class] | +| Added | **`static`** **`public`** | | **[`CharMatcher`]** | **`javaUpperCase`**() | | | ![Method added to public class] | +| Added | **`static`** **`public`** | | **[`CharMatcher`]** | **`none`**() | | | ![Method added to public class] | +| Added | **`static`** **`public`** | | **[`CharMatcher`]** | **`singleWidth`**() | | | ![Method added to public class] | +| Added | **`static`** **`public`** | | **[`CharMatcher`]** | **`whitespace`**() | | | ![Method added to public class] | + +___ + + +### `com.google.common.base.Defaults` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Defaults` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.base.Enums` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|---------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Enums` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.base.Equivalence` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|---------------------|-------|---------------|------------|-------|---------------------|-----------------------| +| Unchanged | `public` `abstract` | Class | `Equivalence` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `T` | [`Object`] | ![No changes] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.base.Functions` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|-------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Functions` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.base.Joiner` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|-----------|-------|----------|------------|-------|---------------------|-----------------------| +| Unchanged | `public` | Class | `Joiner` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|----------|------------|-----------------------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `final` `public` | | [`String`] | `join`([`Iterable`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | | [`String`] | `join`([`Iterator`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | | [`String`] | `join`([`Object[]`][1]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | | [`String`] | `join`([`Object`], [`Object`], [`Object...`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`Joiner`] | `on`([`String`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`Joiner`] | `on`(`char`) | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.base.Joiner$MapJoiner` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|---------------------------|-------|-------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `static` `public` | Class | `MapJoiner` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-----------|----------|------------|-----------------------------------------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `public` | | [`String`] | `join`([`Map`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `public` | | [`String`] | `join`([`Iterable>`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `public` | | [`String`] | `join`([`Iterator>`]) | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.base.MoreObjects` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|---------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `MoreObjects` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|--------------------------|--------------------|--------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | \<[`T extends Object`]\> | [`Object`] | `firstNonNull`(`T`, `T`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`ToStringHelper`] | `toStringHelper`([`Object`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`ToStringHelper`] | `toStringHelper`([`Class`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`ToStringHelper`] | `toStringHelper`([`String`]) | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.base.MoreObjects$ToStringHelper` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|---------------------------|-------|------------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `static` `public` | Class | `ToStringHelper` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-----------|----------|------------|--------------|--------------------------|--------|-----------------------| +| Unchanged | `public` | | [`String`] | `toString`() | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.base.Objects` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|-----------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Objects` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|--------------------------|-----------------------|--------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | \<[`T extends Object`]\> | [`Object`] | `firstNonNull`(`T`, `T`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | `int` | `hashCode`([`Object...`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`ToStringHelper`][2] | `toStringHelper`([`Object`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`ToStringHelper`][2] | `toStringHelper`([`Class`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`ToStringHelper`][2] | `toStringHelper`([`String`]) | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.base.Optional` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|---------------------|-------|------------|------------|-------|---------------|-----------------------| +| Unchanged | `public` `abstract` | Class | `Optional` | [`Object`] | JDK 6 | ![Compatible] | ![Annotation added] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `T` | [`Object`] | ![No changes] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.base.Predicates` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|--------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Predicates` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.base.Splitter` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Splitter` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|----------|----------------------|---------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | | [`Splitter`] | `fixedLength`(`int`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`Splitter`] | `on`(`char`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`Splitter`] | `on`([`CharMatcher`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`Splitter`] | `on`([`String`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`Splitter`] | `on`([`Pattern`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`Splitter`] | `onPattern`([`String`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `public` | | [`Iterable`] | `split`([`CharSequence`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `public` | | [`List`] | `splitToList`([`CharSequence`]) | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.base.Splitter$MapSplitter` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|---------------------------|-------|---------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `static` `public` | Class | `MapSplitter` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-----------|----------|-------------------------|---------------------------|--------------------------|--------|-----------------------| +| Unchanged | `public` | | [`Map`] | `split`([`CharSequence`]) | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.base.StandardSystemProperty` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|------|--------------------------|-------------|-------|---------------|-----------------------| +| Unchanged | `final` `public` | Enum | `StandardSystemProperty` | [`Enum`] | JDK 6 | ![Compatible] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.base.Stopwatch` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|-------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Stopwatch` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|----------|---------------|-------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | | [`Stopwatch`] | `createStarted`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`Stopwatch`] | `createStarted`([`Ticker`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`Stopwatch`] | `createUnstarted`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`Stopwatch`] | `createUnstarted`([`Ticker`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `public` | | `long` | `elapsed`([`TimeUnit`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `public` | | `boolean` | `isRunning`() | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.base.Strings` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|-----------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Strings` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.base.Suppliers` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|-------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Suppliers` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.base.Throwables` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|--------------|------------|-------|---------------------|-----------------------| +| Modified | `final` `public` | Class | `Throwables` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|---------------------------|----------|---------------------------------|----------------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | | [`List`] | `getCausalChain`([`Throwable`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`Throwable`] | `getRootCause`([`Throwable`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`String`] | `getStackTraceAsString`([`Throwable`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Added | **`static`** **`public`** | | **[`List`]** | **`lazyStackTrace`**([`Throwable`]) | **[`CheckReturnValue`]** | | ![Method added to public class] ![Annotation added] | +| Added | **`static`** **`public`** | | **`boolean`** | **`lazyStackTraceIsLazy`**() | **[`CheckReturnValue`]** | | ![Method added to public class] ![Annotation added] | + +___ + + +### `com.google.common.base.Ticker` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|---------------------|-------|----------|------------|-------|---------------------|-----------------------| +| Unchanged | `public` `abstract` | Class | `Ticker` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|----------|------------|------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | | [`Ticker`] | `systemTicker`() | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.base.Utf8` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|--------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Utf8` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|----------|-----------|----------------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | | `int` | `encodedLength`([`CharSequence`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | `boolean` | `isWellFormed`(`byte[]`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | `boolean` | `isWellFormed`(`byte[]`, `int`, `int`) | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.base.VerifyException` + +- [X] Binary-compatible +- [X] Source-compatible +- [ ] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|-----------|-------|-------------------|----------------------|-------|-------------------------------------|-----------------------| +| Modified | `public` | Class | `VerifyException` | [`RuntimeException`] | JDK 6 | ![Default serialversionuid changed] | ![No changes] | + + +#### Constructors + +| Status | Modifiers | Generics | Constructor | Annotations | Throws | Compatibility Changes | +|--------|--------------|----------|--------------------------------------------------|-------------|--------|-----------------------| +| Added | **`public`** | | **`VerifyException`**([`Throwable`]) | | | ![No changes] | +| Added | **`public`** | | **`VerifyException`**([`String`], [`Throwable`]) | | | ![No changes] | + +___ + + +### `com.google.common.cache.CacheLoader$UnsupportedLoadingOperationException` + +- [X] Binary-compatible +- [X] Source-compatible +- [ ] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|-------------------------------|-------|------------------------------------|-----------------------------------|-------|-------------------------------------|-----------------------| +| Modified | `final` `static` **`public`** | Class | `UnsupportedLoad…erationException` | [`UnsupportedOperationException`] | JDK 6 | ![Default serialversionuid changed] | ![No changes] | + +___ + + +### `com.google.common.cache.RemovalNotification` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|-----------------------|------------|-------|---------------------|-----------------------| +| Modified | `final` `public` | Class | `RemovalNotification` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `K` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|---------------------------|--------------------------------------------------------|-----------------------------------|------------------------------------------|-------------|--------|-----------------------| +| Added | **`static`** **`public`** | \<**[`K extends Object`]**, **[`V extends Object`]**\> | **[`RemovalNotification`]** | **`create`**(`K`, `V`, [`RemovalCause`]) | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.BiMap` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|---------------------|-----------|---------|------------|-------|---------------------|-----------------------| +| Unchanged | `public` `abstract` | Interface | `BiMap` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `K` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|---------------------|----------|------------|----------------------|------------------|--------|-----------------------| +| Unchanged | `public` `abstract` | | [`Object`] | `forcePut`(`K`, `V`) | **[`Nullable`]** | | ![Annotation added] | +| Unchanged | `public` `abstract` | | [`Object`] | `put`(`K`, `V`) | **[`Nullable`]** | | ![Annotation added] | + +___ + + +### `com.google.common.collect.Collections2` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|----------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Collections2` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|--------------------------|-------------------|-------------------------------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | \<[`E extends Object`]\> | [`Collection`] | `filter`([`Collection`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.collect.ComparisonChain` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------|-------|-------------------|------------|-------|---------------------|-----------------------| +| Modified | `public` `abstract` | Class | `ComparisonChain` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|--------------------------|----------|-------------------------|-----------------------------------------|--------------------|--------|-----------------------| +| Added | **`final`** **`public`** | | **[`ComparisonChain`]** | **`compare`**([`Boolean`], [`Boolean`]) | **[`Deprecated`]** | | ![Method added to public class] ![Annotation deprecated added] | + +___ + + +### `com.google.common.collect.FluentIterable` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------|-------|------------------|------------|-------|---------------------|-----------------------| +| Modified | `public` `abstract` | Class | `FluentIterable` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `E` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|--------------------------|--------------------------|---------------------------------|-------------------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `final` `public` | | `boolean` | `allMatch`([`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | | `boolean` | `anyMatch`([`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | | `boolean` | `contains`([`Object`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | | [`Optional`] | `first`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | | [`Optional`] | `firstMatch`([`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`E extends Object`]\> | [`FluentIterable`] | `from`([`Iterable`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`E extends Object`]\> | [`FluentIterable`] | `from`([`FluentIterable`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | | [`Object`] | `get`(`int`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | \<[`K extends Object`]\> | [`ImmutableListMultimap`] | `index`([`Function`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | | `boolean` | `isEmpty`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | | [`String`] | `join`([`Joiner`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | | [`Optional`] | `last`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`E extends Object`]\> | [`FluentIterable`] | `of`([`Object[]`][1]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | | `int` | `size`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | | [`Object[]`][1] | `toArray`([`Class`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | | [`ImmutableList`] | `toList`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | \<[`V extends Object`]\> | [`ImmutableMap`] | `toMap`([`Function`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Added | **`final`** **`public`** | | **[`ImmutableMultiset`]** | **`toMultiset`**() | **[`CheckReturnValue`]** | | ![Method added to public class] ![Annotation added] | +| Unchanged | `final` `public` | | [`ImmutableSet`] | `toSet`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | | [`ImmutableList`] | `toSortedList`([`Comparator`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | | [`ImmutableSortedSet`] | `toSortedSet`([`Comparator`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `public` | | [`String`] | `toString`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | \<[`T extends Object`]\> | [`FluentIterable`] | `transform`([`Function`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `public` | \<[`T extends Object`]\> | [`FluentIterable`] | `transformAndConcat`([`Function>`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `final` `public` | \<[`K extends Object`]\> | [`ImmutableMap`] | `uniqueIndex`([`Function`]) | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.collect.HashBiMap` + +- [X] Binary-compatible +- [ ] Source-compatible +- [ ] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|-------------|---------|-------|------------------------|-----------------------| +| Modified | `final` `public` | Class | `HashBiMap` | ~~[`AbstractMap`]~~ → **[`IteratorBasedAbstractMap`]** | JDK 6 | ![Superclass modified] | ![Superclass added] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `K` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|---------------------|---------------------------------------|----------|---------------------------------------------|--------------|-------------|--------|-----------------------| +| Source-incompatible | `public` **`bridge`** **`synthetic`** | | ~~[`Set>`]~~ → **[`Set`]** | `entrySet`() | | | ![Method return type generics changed] | + +___ + + +### `com.google.common.collect.ImmutableBiMap` + +- [X] Binary-compatible +- [X] Source-compatible +- [ ] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------|-------|------------------|------------------------|-------|-------------------------------------|-----------------------| +| Modified | `public` `abstract` | Class | `ImmutableBiMap` | [`ImmutableMap`] | JDK 6 | ![Default serialversionuid changed] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `K` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|---------------------------|--------------------------------------------------------|------------------------------|--------|-------------|--------|-----------------------| +| Added | **`static`** **`public`** | \<**[`K extends Object`]**, **[`V extends Object`]**\> | **[`ImmutableBiMap`]** | **`copyOf`**([`Iterable>`]) | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.ImmutableBiMap$Builder` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------------|-------|-----------|-------------------|-------|---------------------|-----------------------| +| Modified | `final` `static` `public` | Class | `Builder` | [`Builder`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `K` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|--------------|----------|--------------------------|------------------------------------------------------|-------------|--------|-----------------------| +| Added | **`public`** | | **[`Builder`][3]** | **`orderEntriesByValue`**([`Comparator`]) | | | ![Method added to public class] | +| Added | **`public`** | | **[`Builder`][3]** | **`put`**([`Entry`]) | | | ![Method added to public class] | +| Added | **`public`** | | **[`Builder`][3]** | **`putAll`**([`Iterable>`]) | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.ImmutableClassToInstanceMap` + +- [X] Binary-compatible +- [X] Source-compatible +- [ ] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|-------------------------------|-------------------------|-------|-------------------------------------|-----------------------| +| Modified | `final` `public` | Class | `ImmutableClassToInstanceMap` | [`ForwardingMap`] | JDK 6 | ![Default serialversionuid changed] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `B` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|---------------------------|-------------------------------------------------|----------------------------------------|-----------------------------|-------------|--------|-----------------------| +| Added | **`static`** **`public`** | \<**[`B extends Object`]**\> | **[`ImmutableClassToInstanceMap`]** | **`of`**() | | | ![Method added to public class] | +| Added | **`static`** **`public`** | \<**[`B extends Object`]**, **`T extends B`**\> | **[`ImmutableClassToInstanceMap`]** | **`of`**([`Class`], `T`) | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.ImmutableCollection` + +- [ ] Binary-compatible +- [ ] Source-compatible +- [ ] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------|-------|-----------------------|---------------------------|-------|-------------------------------------|-----------------------| +| Modified | `public` `abstract` | Class | `ImmutableCollection` | [`AbstractCollection`] | JDK 6 | ![Default serialversionuid changed] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `E` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|----------|-------------------------|----------|-----------|------------------------|-------------|--------|-----------------------| +| Modified | `public` **`abstract`** | | `boolean` | `contains`([`Object`]) | | | ![Method now abstract] | + +___ + + +### `com.google.common.collect.ImmutableList` + +- [X] Binary-compatible +- [X] Source-compatible +- [ ] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------------------------|---------------------|-------|-----------------|----------------------------|-------|-------------------------------------|-----------------------| +| Serialization-incompatible | `public` `abstract` | Class | `ImmutableList` | [`ImmutableCollection`] | JDK 6 | ![Default serialversionuid changed] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `E` | [`Object`] | ![No changes] | + +___ + + +### `com.google.common.collect.ImmutableListMultimap` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|-----------|-------|-------------------------|-----------------------------|-------|---------------|-----------------------| +| Modified | `public` | Class | `ImmutableListMultimap` | [`ImmutableMultimap`] | JDK 6 | ![Compatible] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `K` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|---------------------------|--------------------------------------------------------|-------------------------------------|--------|-------------|--------|-----------------------| +| Added | **`static`** **`public`** | \<**[`K extends Object`]**, **[`V extends Object`]**\> | **[`ImmutableListMultimap`]** | **`copyOf`**([`Iterable>`]) | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.ImmutableListMultimap$Builder` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------------|-------|-----------|----------------------|-------|---------------------|-----------------------| +| Modified | `final` `static` `public` | Class | `Builder` | [`Builder`][4] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `K` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|--------------|----------|--------------------------|--------|-------------|--------|-----------------------| +| Added | **`public`** | | **[`Builder`][5]** | **`putAll`**([`Iterable>`]) | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.ImmutableMap` + +- [X] Binary-compatible +- [X] Source-compatible +- [ ] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------|-------|----------------|------------|-------|-------------------------------------|-----------------------| +| Modified | `public` `abstract` | Class | `ImmutableMap` | [`Object`] | JDK 6 | ![Default serialversionuid changed] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `K` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|---------------------------|--------------------------------------------------------|-------------------------------|--------|-------------|--------|-----------------------| +| Added | **`static`** **`public`** | \<**[`K extends Object`]**, **[`V extends Object`]**\> | **[`ImmutableMap`][6]** | **`copyOf`**([`Iterable>`]) | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.ImmutableMap$Builder` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|-------------------|-------|-----------|------------|-------|---------------------|-----------------------| +| Modified | `static` `public` | Class | `Builder` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `K` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|--------------|----------|--------------------------|------------------------------------------------------|-------------|--------|-----------------------| +| Added | **`public`** | | **[`Builder`][7]** | **`orderEntriesByValue`**([`Comparator`]) | | | ![Method added to public class] | +| Added | **`public`** | | **[`Builder`][7]** | **`putAll`**([`Iterable>`]) | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.ImmutableMultimap` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------|-------|---------------------|----------------------------|-------|---------------|-----------------------| +| Modified | `public` `abstract` | Class | `ImmutableMultimap` | [`AbstractMultimap`] | JDK 6 | ![Compatible] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `K` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|---------------------------|--------------------------------------------------------|------------------------------------|--------|-------------|--------|-----------------------| +| Added | **`static`** **`public`** | \<**[`K extends Object`]**, **[`V extends Object`]**\> | **[`ImmutableMultimap`][8]** | **`copyOf`**([`Iterable>`]) | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.ImmutableMultimap$Builder` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|-------------------|-------|-----------|------------|-------|---------------------|-----------------------| +| Modified | `static` `public` | Class | `Builder` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `K` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|--------------|----------|--------------------------|--------|-------------|--------|-----------------------| +| Added | **`public`** | | **[`Builder`][9]** | **`putAll`**([`Iterable>`]) | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.ImmutableMultiset` + +- [X] Binary-compatible +- [X] Source-compatible +- [ ] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------|-------|---------------------|----------------------------|-------|-------------------------------------|-----------------------| +| Modified | `public` `abstract` | Class | `ImmutableMultiset` | [`ImmutableCollection`] | JDK 6 | ![Default serialversionuid changed] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `E` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|---------|--------------|----------|---------------|--------------------------------------|-------------|--------|-----------------------| +| Removed | ~~`public`~~ | | ~~`boolean`~~ | ~~`containsAll`~~([`Collection`]) | | | ![No changes] | + +___ + + +### `com.google.common.collect.ImmutableRangeMap` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|-----------|-------|---------------------|------------|-------|---------------|-----------------------| +| Modified | `public` | Class | `ImmutableRangeMap` | [`Object`] | JDK 6 | ![Compatible] | ![Interface added] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|-------------------|-----------------------| +| Unchanged | `K` | [`Comparable`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Implemented Interfaces + +| Status | Interface | Compatibility Changes | +|---------------------|----------------------|-----------------------| +| Source-incompatible | [`RangeMap`] | ![No changes] | +| Added | **[`Serializable`]** | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|--------------|----------|-----------------------------------|---------------------------------|-------------|--------|-----------------------| +| Added | **`public`** | | **[`ImmutableMap, V>`]** | **`asDescendingMapOfRanges`**() | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.ImmutableRangeSet` + +- [X] Binary-compatible +- [X] Source-compatible +- [ ] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|---------------------|-------------------------|-------|-------------------------------------|-----------------------| +| Modified | `final` `public` | Class | `ImmutableRangeSet` | [`AbstractRangeSet`] | JDK 6 | ![Default serialversionuid changed] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|----------------|-----------------------| +| Unchanged | `C` | [`Comparable`] | ![No changes] | + + +#### Implemented Interfaces + +| Status | Interface | Compatibility Changes | +|---------------------|-----------------|-----------------------| +| Source-incompatible | [`RangeSet`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|--------------|----------|--------------------------------|---------------------------------|-------------|--------|-----------------------| +| Added | **`public`** | | **[`ImmutableSet>`]** | **`asDescendingSetOfRanges`**() | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.ImmutableSetMultimap` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|-----------|-------|------------------------|-----------------------------|-------|---------------|-----------------------| +| Modified | `public` | Class | `ImmutableSetMultimap` | [`ImmutableMultimap`] | JDK 6 | ![Compatible] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `K` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|---------------------------|--------------------------------------------------------|------------------------------------|--------|-------------|--------|-----------------------| +| Added | **`static`** **`public`** | \<**[`K extends Object`]**, **[`V extends Object`]**\> | **[`ImmutableSetMultimap`]** | **`copyOf`**([`Iterable>`]) | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.ImmutableSetMultimap$Builder` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------------|-------|-----------|----------------------|-------|---------------------|-----------------------| +| Modified | `final` `static` `public` | Class | `Builder` | [`Builder`][4] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `K` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|--------------|----------|---------------------------|--------|-------------|--------|-----------------------| +| Added | **`public`** | | **[`Builder`][10]** | **`putAll`**([`Iterable>`]) | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.ImmutableSortedMap` + +- [ ] Binary-compatible +- [ ] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|-------------------------------------|-------|----------------------|--------------------------------------------|-------|---------------|-----------------------| +| Modified | **`final`** `public` ~~`abstract`~~ | Class | `ImmutableSortedMap` | [`ImmutableSortedMapFauxverideShim`] | JDK 6 | ![Compatible] | ![Class now final] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `K` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|----------|---------------------------|--------------------------------------------------------|----------------------------------|---------------------------------|-------------|--------|-----------------------| +| Removed | ~~`public`~~ | | ~~`boolean`~~ | ~~`containsValue`~~([`Object`]) | | | ![No changes] | +| Added | **`static`** **`public`** | \<**[`K extends Object`]**, **[`V extends Object`]**\> | **[`ImmutableSortedMap`]** | **`copyOf`**([`Iterable>`]) | | | ![Method added to public class] | +| Added | **`static`** **`public`** | \<**[`K extends Object`]**, **[`V extends Object`]**\> | **[`ImmutableSortedMap`]** | **`copyOf`**([`Iterable>`], [`Comparator`]) | | | ![Method added to public class] | +| Added | **`public`** | | **[`Object`]** | **`get`**([`Object`]) | | | ![Method added to public class] | +| Modified | `public` ~~`abstract`~~ | | [`ImmutableSortedMap`] | `headMap`(`K`, `boolean`) | | | ![No changes] | +| Modified | `public` ~~`abstract`~~ | | [`ImmutableSortedSet`] | `keySet`() | | | ![No changes] | +| Modified | `public` ~~`abstract`~~ | | [`ImmutableSortedMap`] | `tailMap`(`K`, `boolean`) | | | ![No changes] | +| Modified | `public` ~~`abstract`~~ | | [`ImmutableCollection`] | `values`() | | | ![No changes] | + +___ + + +### `com.google.common.collect.ImmutableSortedMap$Builder` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|-------------------|-------|-----------|-------------------|-------|---------------------|-----------------------| +| Modified | `static` `public` | Class | `Builder` | [`Builder`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `K` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|--------------|----------|---------------------------|------------------------------------------------------|--------------------|--------|-----------------------| +| Added | **`public`** | | **[`Builder`][11]** | **`orderEntriesByValue`**([`Comparator`]) | **[`Deprecated`]** | | ![Method added to public class] ![Annotation deprecated added] | +| Added | **`public`** | | **[`Builder`][11]** | **`putAll`**([`Iterable>`]) | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.ImmutableSortedMultiset` + +- [X] Binary-compatible +- [ ] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|---------------------|---------------------|-------|---------------------------|-----------------------------------------|-------|---------------|-----------------------| +| Source-incompatible | `public` `abstract` | Class | `ImmutableSortedMultiset` | [`ImmutableSorted…etFauxverideShim`] | JDK 6 | ![Compatible] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `E` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|---------------------|-------------------|----------|----------------|------------------|-------------|--------|-----------------------| +| Source-incompatible | `static` `public` | \<~~[`E extends Comparable`]~~ → **[`E extends Comparable`]**\> | [`Builder`] | `naturalOrder`() | | | ![Class generic template generics changed] | +| Source-incompatible | `static` `public` | \<~~[`E extends Comparable`]~~ → **[`E extends Comparable`]**\> | [`Builder`] | `reverseOrder`() | | | ![Class generic template generics changed] | + +___ + + +### `com.google.common.collect.ImmutableSortedSet` + +- [X] Binary-compatible +- [X] Source-compatible +- [ ] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------------------------|---------------------|-------|----------------------|-----------------------------------------|-------|-------------------------------------|-----------------------| +| Serialization-incompatible | `public` `abstract` | Class | `ImmutableSortedSet` | [`ImmutableSortedSetFauxverideShim`] | JDK 6 | ![Default serialversionuid changed] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `E` | [`Object`] | ![No changes] | + +___ + + +### `com.google.common.collect.Iterables` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|-------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Iterables` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|------------------------------------------------|-----------------|-----------------------------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | | `boolean` | `elementsEqual`([`Iterable`], [`Iterable`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`T extends Object`]\> | [`Iterable`] | `filter`([`Iterable`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`T extends Object`]\> | [`Iterable`] | `filter`([`Iterable`], [`Class`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`F extends Object`], [`T extends Object`]\> | [`Iterable`] | `transform`([`Iterable`], [`Function`]) | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.collect.Iterators` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|-------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Iterators` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|--------------------------|-----------------------------|-----------------------------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | \<[`T extends Object`]\> | [`UnmodifiableIterator`] | `filter`([`Iterator`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`T extends Object`]\> | [`UnmodifiableIterator`] | `filter`([`Iterator`], [`Class`]) | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.collect.Lists` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|---------|------------|-------|---------------------|-----------------------| +| Modified | `final` `public` | Class | `Lists` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-----------------------|------------------------------------------------|-------------------|----------------------------------------------------------------|--------------------------|--------|-----------------------| +| Modified | `static` **`public`** | \<[`B extends Object`]\> | [`List>`] | `cartesianProduct`([`List>`]) | | | ![No changes] | +| Modified | `static` **`public`** | \<[`B extends Object`]\> | [`List>`] | `cartesianProduct`([`List...`]) | | | ![No changes] | +| Unchanged | `static` `public` | \<[`T extends Object`]\> | [`List`] | `reverse`([`List`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`F extends Object`], [`T extends Object`]\> | [`List`] | `transform`([`List`], [`Function`]) | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.collect.MapConstraint` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|---------------------|-----------|-----------------|------------|-------|---------------------|-----------------------| +| Unchanged | `public` `abstract` | Interface | `MapConstraint` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation deprecated added] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `K` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------|-----------------------| +| Added | **[`Deprecated`]** | ![No changes] | + +___ + + +### `com.google.common.collect.MapConstraints` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|------------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `MapConstraints` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation deprecated added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------|-----------------------| +| Added | **[`Deprecated`]** | ![No changes] | + +___ + + +### `com.google.common.collect.MapMaker` + +- [ ] Binary-compatible +- [ ] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|------------|-----------------------------|-------|---------------------|-----------------------| +| Modified | `final` `public` | Class | `MapMaker` | [`GenericMapMaker`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|----------|--------------|----------|--------------|----------------|-------------|--------|-----------------------| +| Modified | ~~`public`~~ | | [`MapMaker`] | `softValues`() | | | ![Method less accessible] | + +___ + + +### `com.google.common.collect.Maps` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|--------|------------|-------|---------------------|-----------------------| +| Modified | `final` `public` | Class | `Maps` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|---------------------------|--------------------------------------------------------|-----------------------------|------------------------------------------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`Map`] | `filterEntries`([`Map`], [`Predicate>`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`SortedMap`] | `filterEntries`([`SortedMap`], [`Predicate>`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`NavigableMap`] | `filterEntries`([`NavigableMap`], [`Predicate>`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`BiMap`] | `filterEntries`([`BiMap`], [`Predicate>`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`Map`] | `filterKeys`([`Map`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`SortedMap`] | `filterKeys`([`SortedMap`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`NavigableMap`] | `filterKeys`([`NavigableMap`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`BiMap`] | `filterKeys`([`BiMap`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`Map`] | `filterValues`([`Map`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`SortedMap`] | `filterValues`([`SortedMap`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`NavigableMap`] | `filterValues`([`NavigableMap`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`BiMap`] | `filterValues`([`BiMap`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Added | **`static`** **`public`** | \<**[`K extends Object`]**, **[`V extends Object`]**\> | **[`LinkedHashMap`]** | **`newLinkedHashMapWithExpectedSize`**(`int`) | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.MultimapBuilder` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|---------------------|-------|-------------------|------------|-------|---------------------|-----------------------| +| Unchanged | `public` `abstract` | Class | `MultimapBuilder` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `K0` | [`Object`] | ![No changes] | +| Unchanged | `V0` | [`Object`] | ![No changes] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.collect.Multimaps` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|-------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Multimaps` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|------------------------------------------------|------------------------|-----------------------------------------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`Multimap`] | `filterEntries`([`Multimap`], [`Predicate>`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`SetMultimap`] | `filterEntries`([`SetMultimap`], [`Predicate>`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`Multimap`] | `filterKeys`([`Multimap`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`SetMultimap`] | `filterKeys`([`SetMultimap`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`ListMultimap`] | `filterKeys`([`ListMultimap`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`Multimap`] | `filterValues`([`Multimap`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`K extends Object`], [`V extends Object`]\> | [`SetMultimap`] | `filterValues`([`SetMultimap`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.collect.Multisets` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|-------------|------------|-------|---------------------|-----------------------| +| Modified | `final` `public` | Class | `Multisets` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|---------------------------|--------------------------|-----------------|-----------------------------------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | \<[`E extends Object`]\> | [`Multiset`] | `filter`([`Multiset`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Added | **`static`** **`public`** | | **`boolean`** | **`removeOccurrences`**([`Multiset`], [`Multiset`]) | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.RangeMap` + +- [X] Binary-compatible +- [ ] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------|-----------|------------|------------|-------|---------------------|-----------------------| +| Modified | `public` `abstract` | Interface | `RangeMap` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|----------------|-----------------------| +| Unchanged | `K` | [`Comparable`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|-----------------------------|----------|--------------------------|---------------------------------|-------------|--------|-----------------------| +| Added | **`public`** **`abstract`** | | **[`Map, V>`]** | **`asDescendingMapOfRanges`**() | | | ![Method added to interface] | + +___ + + +### `com.google.common.collect.RangeSet` + +- [X] Binary-compatible +- [ ] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------|-----------|------------|------------|-------|---------------------|-----------------------| +| Modified | `public` `abstract` | Interface | `RangeSet` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|----------------|-----------------------| +| Unchanged | `C` | [`Comparable`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|-----------------------------|----------|-----------------------|---------------------------------|-------------|--------|-----------------------| +| Added | **`public`** **`abstract`** | | **[`Set>`]** | **`asDescendingSetOfRanges`**() | | | ![Method added to interface] | + +___ + + +### `com.google.common.collect.Sets` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|--------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Sets` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|--------------------------|---------------------|---------------------------------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | \<[`E extends Object`]\> | [`Set`] | `filter`([`Set`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`E extends Object`]\> | [`SortedSet`] | `filter`([`SortedSet`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`E extends Object`]\> | [`NavigableSet`] | `filter`([`NavigableSet`], [`Predicate`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`E extends Object`]\> | [`Set`] | `newSetFromMap`([`Map`]) | **[`Deprecated`]** | | ![Annotation deprecated added] | + +___ + + +### `com.google.common.collect.Table` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|---------------------|-----------|---------|------------|-------|---------------------|-----------------------| +| Unchanged | `public` `abstract` | Interface | `Table` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `C` | [`Object`] | ![No changes] | +| Unchanged | `R` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|---------------------|----------|------------|----------------------------------|------------------|--------|-----------------------| +| Unchanged | `public` `abstract` | | [`Object`] | `put`(`R`, `C`, `V`) | **[`Nullable`]** | | ![Annotation added] | +| Unchanged | `public` `abstract` | | [`Object`] | `remove`([`Object`], [`Object`]) | **[`Nullable`]** | | ![Annotation added] | + +___ + + +### `com.google.common.collect.Table$Cell` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------------------|-----------|--------|------------|-------|---------------------|-----------------------| +| Unchanged | `static` `public` `abstract` | Interface | `Cell` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `C` | [`Object`] | ![No changes] | +| Unchanged | `R` | [`Object`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|---------------------|----------|------------|------------------|------------------|--------|-----------------------| +| Unchanged | `public` `abstract` | | [`Object`] | `getColumnKey`() | **[`Nullable`]** | | ![Annotation added] | +| Unchanged | `public` `abstract` | | [`Object`] | `getRowKey`() | **[`Nullable`]** | | ![Annotation added] | +| Unchanged | `public` `abstract` | | [`Object`] | `getValue`() | **[`Nullable`]** | | ![Annotation added] | + +___ + + +### `com.google.common.collect.TreeRangeMap` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|----------------|------------|-------|---------------------|-----------------------| +| Modified | `final` `public` | Class | `TreeRangeMap` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|----------------|-----------------------| +| Unchanged | `K` | [`Comparable`] | ![No changes] | +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Implemented Interfaces + +| Status | Interface | Compatibility Changes | +|---------------------|--------------------|-----------------------| +| Source-incompatible | [`RangeMap`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|--------------|----------|--------------------------|---------------------------------|-------------|--------|-----------------------| +| Added | **`public`** | | **[`Map, V>`]** | **`asDescendingMapOfRanges`**() | | | ![Method added to public class] | + +___ + + +### `com.google.common.collect.TreeRangeSet` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|-----------|-------|----------------|-------------------------|-------|---------------------|-----------------------| +| Modified | `public` | Class | `TreeRangeSet` | [`AbstractRangeSet`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|-------------------|-----------------------| +| Unchanged | `C` | [`Comparable`] | ![No changes] | + + +#### Implemented Interfaces + +| Status | Interface | Compatibility Changes | +|---------------------|-----------------|-----------------------| +| Source-incompatible | [`RangeSet`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|--------------|----------|-----------------------|---------------------------------|-------------|--------|-----------------------| +| Added | **`public`** | | **[`Set>`]** | **`asDescendingSetOfRanges`**() | | | ![Method added to public class] | + +___ + + +### `com.google.common.eventbus.AsyncEventBus` + +- [ ] Binary-compatible +- [ ] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|-----------|-------|-----------------|--------------|-------|---------------------|-----------------------| +| Modified | `public` | Class | `AsyncEventBus` | [`EventBus`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|---------|-----------------|----------|------------|------------------------------|-------------|--------|-----------------------| +| Removed | ~~`protected`~~ | | ~~`void`~~ | ~~`dispatchQueuedEvents`~~() | | | ![Method removed] | + +___ + + +### `com.google.common.eventbus.DeadEvent` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|-----------|-------|-------------|------------|-------|---------------------|-----------------------| +| Modified | `public` | Class | `DeadEvent` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|--------------|----------|----------------|------------------|-------------|--------|-----------------------| +| Added | **`public`** | | **[`String`]** | **`toString`**() | | | ![Method added to public class] | + +___ + + +### `com.google.common.eventbus.EventBus` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|-----------|-------|------------|------------|-------|---------------------|-----------------------| +| Modified | `public` | Class | `EventBus` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|--------------------------|----------|----------------|--------------------|-------------|--------|-----------------------| +| Added | **`final`** **`public`** | | **[`String`]** | **`identifier`**() | | | ![Method added to public class] | +| Added | **`public`** | | **[`String`]** | **`toString`**() | | | ![Method added to public class] | + +___ + + +### `com.google.common.hash.BloomFilter` + +- [X] Binary-compatible +- [X] Source-compatible +- [ ] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|---------------|------------|-------|-------------------------------------|-----------------------| +| Modified | `final` `public` | Class | `BloomFilter` | [`Object`] | JDK 6 | ![Default serialversionuid changed] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `T` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|---------------------------|------------------------------|------------------------|-------------------------------------------------------|--------------------------|-----------------|-----------------------| +| Unchanged | `public` | | `boolean` | `apply`(`T`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `public` | | [`BloomFilter`] | `copy`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`T extends Object`]\> | [`BloomFilter`] | `create`([`Funnel`], `int`, `double`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`T extends Object`]\> | [`BloomFilter`] | `create`([`Funnel`], `int`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Added | **`static`** **`public`** | \<**[`T extends Object`]**\> | **[`BloomFilter`]** | **`create`**([`Funnel`], `long`, `double`) | **[`CheckReturnValue`]** | | ![Method added to public class] ![Annotation added] | +| Added | **`static`** **`public`** | \<**[`T extends Object`]**\> | **[`BloomFilter`]** | **`create`**([`Funnel`], `long`) | **[`CheckReturnValue`]** | | ![Method added to public class] ![Annotation added] | +| Unchanged | `public` | | `double` | `expectedFpp`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `public` | | `boolean` | `isCompatible`([`BloomFilter`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `public` | | `boolean` | `mightContain`(`T`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`T extends Object`]\> | [`BloomFilter`] | `readFrom`([`InputStream`], [`Funnel`]) | **[`CheckReturnValue`]** | [`IOException`] | ![Annotation added] | + +___ + + +### `com.google.common.hash.Funnels` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|-----------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Funnels` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.hash.HashCode` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|---------------------|-------|------------|------------|-------|---------------------|-----------------------| +| Unchanged | `public` `abstract` | Class | `HashCode` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|---------------------|----------|--------------|--------------------------|--------------------------|--------|-----------------------| +| Unchanged | `public` `abstract` | | `byte[]` | `asBytes`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `public` `abstract` | | `int` | `asInt`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `public` `abstract` | | `long` | `asLong`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `public` `abstract` | | `int` | `bits`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`HashCode`] | `fromBytes`(`byte[]`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`HashCode`] | `fromInt`(`int`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`HashCode`] | `fromLong`(`long`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`HashCode`] | `fromString`([`String`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `public` `abstract` | | `long` | `padToLong`() | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.hash.Hasher` + +- [X] Binary-compatible +- [ ] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------|-----------|----------|------------|-------|---------------------|-----------------------| +| Modified | `public` `abstract` | Interface | `Hasher` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-----------------------------|----------|--------------|------------------|--------------------------|--------|-----------------------| +| Unchanged | `public` `abstract` | | [`HashCode`] | `hash`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Added | **`public`** **`abstract`** | | **`int`** | **`hashCode`**() | **[`Deprecated`]** | | ![Method added to interface] ![Annotation deprecated added] | + +___ + + +### `com.google.common.hash.Hashing` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|-----------|------------|-------|---------------------|-----------------------| +| Modified | `final` `public` | Class | `Hashing` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|---------------------------|----------|----------------------|-------------------------------------------------|-------------|--------|-----------------------| +| Added | **`static`** **`public`** | | **[`HashFunction`]** | **`concatenating`**([`HashFunction`], [`HashFunction`], [`HashFunction...`]) | | | ![Method added to public class] | +| Added | **`static`** **`public`** | | **[`HashFunction`]** | **`concatenating`**([`Iterable`]) | | | ![Method added to public class] | +| Added | **`static`** **`public`** | | **[`HashFunction`]** | **`sha384`**() | | | ![Method added to public class] | + +___ + + +### `com.google.common.hash.HashingInputStream` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|----------------------|-----------------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `HashingInputStream` | [`FilterInputStream`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-----------|----------|--------------|-------------------|--------------------------|--------|-----------------------| +| Unchanged | `public` | | [`HashCode`] | `hash`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `public` | | `boolean` | `markSupported`() | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.hash.HashingOutputStream` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|-----------------------|------------------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `HashingOutputStream` | [`FilterOutputStream`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-----------|----------|--------------|----------|--------------------------|--------|-----------------------| +| Unchanged | `public` | | [`HashCode`] | `hash`() | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.io.BaseEncoding` + +- [ ] Binary-compatible +- [ ] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------|-------|----------------|------------|-------|---------------------|-----------------------| +| Modified | `public` `abstract` | Class | `BaseEncoding` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|----------|-------------------------------------|----------|------------------|------------------------------|-------------|--------|-----------------------| +| Modified | ~~`final`~~ `public` **`abstract`** | | [`InputStream`] | `decodingStream`([`Reader`]) | | | ![Method now abstract] | +| Modified | ~~`final`~~ `public` **`abstract`** | | [`OutputStream`] | `encodingStream`([`Writer`]) | | | ![Method now abstract] | + +___ + + +### `com.google.common.io.ByteSource` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------|-------|--------------|------------|-------|---------------------|-----------------------| +| Modified | `public` `abstract` | Class | `ByteSource` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|--------------|----------|------------------------|---------------------|-------------|--------|-----------------------| +| Added | **`public`** | | **[`Optional`]** | **`sizeIfKnown`**() | | | ![Method added to public class] | + +___ + + +### `com.google.common.io.CharSource` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------|-------|--------------|------------|-------|---------------------|-----------------------| +| Modified | `public` `abstract` | Class | `CharSource` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|--------------|----------|------------------------|-----------------------|-------------|---------------------|-----------------------| +| Added | **`public`** | | **`long`** | **`length`**() | | **[`IOException`]** | ![Method added to public class] | +| Added | **`public`** | | **[`Optional`]** | **`lengthIfKnown`**() | | | ![Method added to public class] | + +___ + + +### `com.google.common.net.HttpHeaders` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|---------------|------------|-------|---------------------|-----------------------| +| Modified | `final` `public` | Class | `HttpHeaders` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Fields + +| Status | Modifiers | Type | Name | Annotations | Compatibility Changes | +|--------|---------------------------------------|----------------|-------------|-------------|-----------------------| +| Added | **`public`** **`static`** **`final`** | **[`String`]** | `PING_FROM` | | ![No changes] | +| Added | **`public`** **`static`** **`final`** | **[`String`]** | `PING_TO` | | ![No changes] | + +___ + + +### `com.google.common.net.MediaType` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|-------------|------------|-------|---------------------|-----------------------| +| Modified | `final` `public` | Class | `MediaType` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Fields + +| Status | Modifiers | Type | Name | Annotations | Compatibility Changes | +|--------|---------------------------------------|-------------------|-----------------------|-------------|-----------------------| +| Added | **`public`** **`static`** **`final`** | **[`MediaType`]** | `APPLE_PASSBOOK` | | ![No changes] | +| Added | **`public`** **`static`** **`final`** | **[`MediaType`]** | `DART_UTF_8` | | ![No changes] | +| Added | **`public`** **`static`** **`final`** | **[`MediaType`]** | `MANIFEST_JSON_UTF_8` | | ![No changes] | + +___ + + +### `com.google.common.primitives.Booleans` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Booleans` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.primitives.Bytes` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|---------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Bytes` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.primitives.Chars` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|---------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Chars` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.primitives.Doubles` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|-----------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Doubles` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|----------|------------|------------------------|----------------------|--------|-----------------------| +| Unchanged | `static` `public` | | [`Double`] | `tryParse`([`String`]) | **[`CheckForNull`]** | | ![Annotation added] | + +___ + + +### `com.google.common.primitives.Floats` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|----------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Floats` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|----------|-----------|------------------------|----------------------|--------|-----------------------| +| Unchanged | `static` `public` | | [`Float`] | `tryParse`([`String`]) | **[`CheckForNull`]** | | ![Annotation added] | + +___ + + +### `com.google.common.primitives.Ints` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|--------|------------|-------|---------------------|-----------------------| +| Modified | `final` `public` | Class | `Ints` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-----------------------|----------|-------------|-------------------------------|------------------|--------|-----------------------| +| Unchanged | `static` `public` | | [`Integer`] | `tryParse`([`String`]) | **[`Nullable`]** | | ![Annotation added] | +| Modified | `static` **`public`** | | [`Integer`] | `tryParse`([`String`], `int`) | **[`Nullable`]** | | ![Annotation added] | + +___ + + +### `com.google.common.primitives.Longs` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|---------|------------|-------|---------------------|-----------------------| +| Modified | `final` `public` | Class | `Longs` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|---------------------------|----------|--------------|-----------------------------------|------------------------------------------|--------|-----------------------| +| Unchanged | `static` `public` | | [`Long`] | `tryParse`([`String`]) | **[`CheckForNull`]**
**[`Nullable`]** | | ![Annotation added] | +| Added | **`static`** **`public`** | | **[`Long`]** | **`tryParse`**([`String`], `int`) | **[`CheckForNull`]**
**[`Nullable`]** | | ![Method added to public class] ![Annotation added] | + +___ + + +### `com.google.common.primitives.Primitives` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|--------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Primitives` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.primitives.Shorts` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|----------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `Shorts` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.primitives.SignedBytes` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|---------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `SignedBytes` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + +___ + + +### `com.google.common.primitives.UnsignedBytes` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|-----------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `UnsignedBytes` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|----------|----------------|-------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | | `int` | `compare`(`byte`, `byte`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`String`] | `join`([`String`], `byte...`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`Comparator`] | `lexicographicalComparator`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | `byte` | `max`(`byte...`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | `byte` | `min`(`byte...`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | `int` | `toInt`(`byte`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`String`] | `toString`(`byte`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`String`] | `toString`(`byte`, `int`) | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.primitives.UnsignedInteger` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|-------------------|------------|-------|---------------|-----------------------| +| Unchanged | `final` `public` | Class | `UnsignedInteger` | [`Number`] | JDK 6 | ![Compatible] | ![Annotation added] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------------|-----------------------| +| Added | **[`CheckReturnValue`]** | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-----------|----------|---------------------|----------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `public` | | [`UnsignedInteger`] | `dividedBy`([`UnsignedInteger`]) | ~~[`CheckReturnValue`]~~ | | ![Annotation removed] | +| Unchanged | `public` | | [`UnsignedInteger`] | `minus`([`UnsignedInteger`]) | ~~[`CheckReturnValue`]~~ | | ![Annotation removed] | +| Unchanged | `public` | | [`UnsignedInteger`] | `mod`([`UnsignedInteger`]) | ~~[`CheckReturnValue`]~~ | | ![Annotation removed] | +| Unchanged | `public` | | [`UnsignedInteger`] | `plus`([`UnsignedInteger`]) | ~~[`CheckReturnValue`]~~ | | ![Annotation removed] | +| Unchanged | `public` | | [`UnsignedInteger`] | `times`([`UnsignedInteger`]) | ~~[`CheckReturnValue`]~~ | | ![Annotation removed] | + +___ + + +### `com.google.common.primitives.UnsignedInts` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|----------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `UnsignedInts` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|----------|----------------|-------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | | `int` | `compare`(`int`, `int`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | `int` | `divide`(`int`, `int`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`String`] | `join`([`String`], `int...`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`Comparator`] | `lexicographicalComparator`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | `int` | `max`(`int...`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | `int` | `min`(`int...`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | `int` | `remainder`(`int`, `int`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | `long` | `toLong`(`int`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`String`] | `toString`(`int`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`String`] | `toString`(`int`, `int`) | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.primitives.UnsignedLong` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|----------------|------------|-------|---------------|-----------------------| +| Unchanged | `final` `public` | Class | `UnsignedLong` | [`Number`] | JDK 6 | ![Compatible] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-----------|----------|------------------|---------------------------|--------------------------|--------|-----------------------| +| Unchanged | `public` | | [`UnsignedLong`] | `minus`([`UnsignedLong`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `public` | | [`UnsignedLong`] | `plus`([`UnsignedLong`]) | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.primitives.UnsignedLongs` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|------------------|-------|-----------------|------------|-------|---------------------|-----------------------| +| Unchanged | `final` `public` | Class | `UnsignedLongs` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|-------------------|----------|----------------|-------------------------------|--------------------------|--------|-----------------------| +| Unchanged | `static` `public` | | `int` | `compare`(`long`, `long`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | `long` | `divide`(`long`, `long`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`String`] | `join`([`String`], `long...`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`Comparator`] | `lexicographicalComparator`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | `long` | `max`(`long...`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | `long` | `min`(`long...`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | `long` | `remainder`(`long`, `long`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`String`] | `toString`(`long`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | | [`String`] | `toString`(`long`, `int`) | **[`CheckReturnValue`]** | | ![Annotation added] | + +___ + + +### `com.google.common.reflect.ClassPath$ResourceInfo` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|-------------------|-------|----------------|------------|-------|---------------------|-----------------------| +| Modified | `static` `public` | Class | `ResourceInfo` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|----------|------------------|----------|---------|---------|-------------|--------------------------------|-----------------------| +| Modified | `final` `public` | | [`URL`] | `url`() | | **[`NoSuchElementException`]** | ![No changes] | + +___ + + +### `com.google.common.reflect.TypeToken` + +- [X] Binary-compatible +- [X] Source-compatible +- [ ] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------|-------|-------------|--------------------|-------|-------------------------------------|-----------------------| +| Modified | `public` `abstract` | Class | `TypeToken` | [`TypeCapture`] | JDK 6 | ![Default serialversionuid changed] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `T` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|--------------------------|----------|---------------|---------------------------------------|--------------------|--------|-----------------------| +| Unchanged | `final` `public` | | `boolean` | `isAssignableFrom`([`TypeToken`]) | **[`Deprecated`]** | | ![Annotation deprecated added] | +| Unchanged | `final` `public` | | `boolean` | `isAssignableFrom`([`Type`]) | **[`Deprecated`]** | | ![Annotation deprecated added] | +| Added | **`final`** **`public`** | | **`boolean`** | **`isSubtypeOf`**([`TypeToken`]) | | | ![Method added to public class] | +| Added | **`final`** **`public`** | | **`boolean`** | **`isSubtypeOf`**([`Type`]) | | | ![Method added to public class] | +| Added | **`final`** **`public`** | | **`boolean`** | **`isSupertypeOf`**([`TypeToken`]) | | | ![Method added to public class] | +| Added | **`final`** **`public`** | | **`boolean`** | **`isSupertypeOf`**([`Type`]) | | | ![Method added to public class] | + +___ + + +### `com.google.common.util.concurrent.AbstractFuture` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------|-------|------------------|------------|-------|---------------------|-----------------------| +| Modified | `public` `abstract` | Class | `AbstractFuture` | [`Object`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|-----------------|----------|---------------|----------------------------------------------------|-------------|--------|-----------------------| +| Added | **`protected`** | | **`boolean`** | **`setFuture`**([`ListenableFuture`]) | | | ![No changes] | + +___ + + +### `com.google.common.util.concurrent.AbstractListeningExecutorService` + +- [ ] Binary-compatible +- [ ] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|---------------------|-------|------------------------------------|-----------------------------|-------|---------------------|-----------------------| +| Modified | `public` `abstract` | Class | `AbstractListeningExecutorService` | [`AbstractExecutorService`] | JDK 6 | ![Not serializable] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|----------|---------------------|--------------------------|------------------------------------------------------------------|---------------------------------|-------------|--------|-----------------------| +| Modified | `final` `protected` | \<[`T extends Object`]\> | ~~[`ListenableFutureTask`]~~ → **[`RunnableFuture`]** | `newTaskFor`([`Runnable`], `T`) | | | ![Method return type changed] | +| Modified | `final` `protected` | \<[`T extends Object`]\> | ~~[`ListenableFutureTask`]~~ → **[`RunnableFuture`]** | `newTaskFor`([`Callable`]) | | | ![Method return type changed] | + +___ + + +### `com.google.common.util.concurrent.FutureFallback` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|-----------|---------------------|-----------|------------------|------------|-------|---------------------|-----------------------| +| Unchanged | `public` `abstract` | Interface | `FutureFallback` | [`Object`] | JDK 6 | ![Not serializable] | ![Annotation deprecated added] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Annotations + +| Status | Annotation | Compatibility Changes | +|--------|--------------------|-----------------------| +| Added | **[`Deprecated`]** | ![No changes] | + +___ + + +### `com.google.common.util.concurrent.Futures` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|-----------|----------------------------------------------------------------|-------|---------------------|-----------------------| +| Modified | `final` `public` | Class | `Futures` | ~~[`Object`]~~ → **[`GwtFuturesCatchingSpecialization`]** | JDK 6 | ![Not serializable] | ![Superclass added] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|-----------|---------------------------|-----------------------------------------------------------|----------------------------------------|----------------------------------------------------------|-------------------------------------------------|-------------------|-----------------------| +| Unchanged | `static` `public` | \<[`V extends Object`]\> | [`ListenableFuture>`] | `allAsList`([`ListenableFuture...`]) | **[`CheckReturnValue`]**
**[`SafeVarargs`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`V extends Object`]\> | [`ListenableFuture>`] | `allAsList`([`Iterable>`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Added | **`static`** **`public`** | \<**[`V extends Object`]**, **[`X extends Throwable`]**\> | **[`ListenableFuture`]** | **`catching`**([`ListenableFuture`], [`Class`], [`Function`]) | **[`CheckReturnValue`]** | | ![Method added to public class] ![Annotation added] | +| Added | **`static`** **`public`** | \<**[`V extends Object`]**, **[`X extends Throwable`]**\> | **[`ListenableFuture`]** | **`catching`**([`ListenableFuture`], [`Class`], [`Function`], [`Executor`]) | **[`CheckReturnValue`]** | | ![Method added to public class] ![Annotation added] | +| Added | **`static`** **`public`** | \<**[`V extends Object`]**, **[`X extends Throwable`]**\> | **[`ListenableFuture`]** | **`catchingAsync`**([`ListenableFuture`], [`Class`], [`AsyncFunction`]) | | | ![Method added to public class] | +| Added | **`static`** **`public`** | \<**[`V extends Object`]**, **[`X extends Throwable`]**\> | **[`ListenableFuture`]** | **`catchingAsync`**([`ListenableFuture`], [`Class`], [`AsyncFunction`], [`Executor`]) | | | ![Method added to public class] | +| Unchanged | `static` `public` | \<[`V extends Object`]\> | [`ListenableFuture`] | `dereference`([`ListenableFuture>`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`V extends Object`], [`X extends Exception`]\> | [`Object`] | `get`([`Future`], [`Class`]) | **[`Deprecated`]** | [`Exception`] | ![Annotation deprecated added] | +| Unchanged | `static` `public` | \<[`V extends Object`], [`X extends Exception`]\> | [`Object`] | `get`([`Future`], `long`, [`TimeUnit`], [`Class`]) | **[`Deprecated`]** | [`Exception`] | ![Annotation deprecated added] | +| Added | **`static`** **`public`** | \<**[`V extends Object`]**, **[`X extends Exception`]**\> | **[`Object`]** | **`getChecked`**([`Future`], [`Class`]) | | **[`Exception`]** | ![Method added to public class] | +| Added | **`static`** **`public`** | \<**[`V extends Object`]**, **[`X extends Exception`]**\> | **[`Object`]** | **`getChecked`**([`Future`], [`Class`], `long`, [`TimeUnit`]) | | **[`Exception`]** | ![Method added to public class] | +| Unchanged | `static` `public` | \<[`V extends Object`]\> | [`ListenableFuture`] | `immediateCancelledFuture`() | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`V extends Object`], [`X extends Exception`]\> | [`CheckedFuture`] | `immediateCheckedFuture`(`V`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`V extends Object`], [`X extends Exception`]\> | [`CheckedFuture`] | `immediateFailedCheckedFuture`(`X`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`V extends Object`]\> | [`ListenableFuture`] | `immediateFailedFuture`([`Throwable`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`V extends Object`]\> | [`ListenableFuture`] | `immediateFuture`(`V`) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`T extends Object`]\> | [`ImmutableList>`] | `inCompletionOrder`([`Iterable>`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`I extends Object`], [`O extends Object`]\> | [`Future`] | `lazyTransform`([`Future`], [`Function`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`V extends Object`], [`X extends Exception`]\> | [`CheckedFuture`] | `makeChecked`([`ListenableFuture`], [`Function`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`V extends Object`]\> | [`ListenableFuture`] | `nonCancellationPropagating`([`ListenableFuture`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`V extends Object`]\> | [`ListenableFuture>`] | `successfulAsList`([`ListenableFuture...`]) | **[`CheckReturnValue`]**
**[`SafeVarargs`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`V extends Object`]\> | [`ListenableFuture>`] | `successfulAsList`([`Iterable>`]) | **[`CheckReturnValue`]** | | ![Annotation added] | +| Unchanged | `static` `public` | \<[`I extends Object`], [`O extends Object`]\> | [`ListenableFuture`] | `transform`([`ListenableFuture`], [`AsyncFunction`]) | **[`Deprecated`]** | | ![Annotation deprecated added] | +| Unchanged | `static` `public` | \<[`I extends Object`], [`O extends Object`]\> | [`ListenableFuture`] | `transform`([`ListenableFuture`], [`AsyncFunction`], [`Executor`]) | **[`Deprecated`]** | | ![Annotation deprecated added] | +| Added | **`static`** **`public`** | \<**[`I extends Object`]**, **[`O extends Object`]**\> | **[`ListenableFuture`]** | **`transformAsync`**([`ListenableFuture`], [`AsyncFunction`]) | | | ![Method added to public class] | +| Added | **`static`** **`public`** | \<**[`I extends Object`]**, **[`O extends Object`]**\> | **[`ListenableFuture`]** | **`transformAsync`**([`ListenableFuture`], [`AsyncFunction`], [`Executor`]) | | | ![Method added to public class] | +| Unchanged | `static` `public` | \<[`V extends Object`]\> | [`ListenableFuture`] | `withFallback`([`ListenableFuture`], [`FutureFallback`]) | **[`CheckReturnValue`]**
**[`Deprecated`]** | | ![Annotation added] ![Annotation deprecated added] | +| Unchanged | `static` `public` | \<[`V extends Object`]\> | [`ListenableFuture`] | `withFallback`([`ListenableFuture`], [`FutureFallback`], [`Executor`]) | **[`CheckReturnValue`]**
**[`Deprecated`]** | | ![Annotation added] ![Annotation deprecated added] | +| Added | **`static`** **`public`** | \<**[`V extends Object`]**\> | **[`ListenableFuture`]** | **`withTimeout`**([`ListenableFuture`], `long`, [`TimeUnit`], [`ScheduledExecutorService`]) | **[`CheckReturnValue`]** | | ![Method added to public class] ![Annotation added] | + +___ + + +### `com.google.common.util.concurrent.SettableFuture` + +- [X] Binary-compatible +- [X] Source-compatible +- [X] Serialization-compatible + +| Status | Modifiers | Type | Name | Extends | JDK | Serialization | Compatibility Changes | +|----------|------------------|-------|------------------|-----------------------------------------------------------|-------|---------------------|-----------------------| +| Modified | `final` `public` | Class | `SettableFuture` | ~~[`AbstractFuture`]~~ → **[`TrustedFuture`]** | JDK 6 | ![Not serializable] | ![Superclass added] | + + +#### Generics + +| Status | Name | Extends | Compatibility Changes | +|-----------|------|------------|-----------------------| +| Unchanged | `V` | [`Object`] | ![No changes] | + + +#### Methods + +| Status | Modifiers | Generics | Type | Method | Annotations | Throws | Compatibility Changes | +|--------|--------------|----------|---------------|----------------------------------------------------|-------------|--------|-----------------------| +| Added | **`public`** | | **`boolean`** | **`setFuture`**([`ListenableFuture`]) | | | ![Method added to public class] | + + +
+ + +___ + +*Generated on: 2024-07-29 17:08:40.539+0000*. + +[1]: # "java.lang.Object[]" +[2]: # "com.google.common.base.Objects$ToStringHelper" +[3]: # "com.google.common.collect.ImmutableBiMap$Builder" +[4]: # "com.google.common.collect.ImmutableMultimap$Builder" +[5]: # "com.google.common.collect.ImmutableListMultimap$Builder" +[6]: # "com.google.common.collect.ImmutableMap" +[7]: # "com.google.common.collect.ImmutableMap$Builder" +[8]: # "com.google.common.collect.ImmutableMultimap" +[9]: # "com.google.common.collect.ImmutableMultimap$Builder" +[10]: # "com.google.common.collect.ImmutableSetMultimap$Builder" +[11]: # "com.google.common.collect.ImmutableSortedMap$Builder" +[Annotation added]: https://img.shields.io/badge/Annotation_added-yellow "Annotation added" +[Annotation deprecated added]: https://img.shields.io/badge/Annotation_deprecated_added-orange "Annotation deprecated added" +[Annotation removed]: https://img.shields.io/badge/Annotation_removed-yellow "Annotation removed" +[Class generic template generics changed]: https://img.shields.io/badge/Class_generic_template_generics_changed-orange "Class generic template generics changed" +[Class now final]: https://img.shields.io/badge/Class_now_final-red "Class now final" +[Compatible]: https://img.shields.io/badge/Compatible-green "Compatible" +[Default serialversionuid changed]: https://img.shields.io/badge/Incompatible-red "Default serialversionuid changed" +[Interface added]: https://img.shields.io/badge/Interface_added-orange "Interface added" +[Method added to interface]: https://img.shields.io/badge/Method_added_to_interface-orange "Method added to interface" +[Method added to public class]: https://img.shields.io/badge/Method_added_to_public_class-yellow "Method added to public class" +[Method less accessible]: https://img.shields.io/badge/Method_less_accessible-red "Method less accessible" +[Method now abstract]: https://img.shields.io/badge/Method_now_abstract-red "Method now abstract" +[Method removed]: https://img.shields.io/badge/Method_removed-red "Method removed" +[Method return type changed]: https://img.shields.io/badge/Method_return_type_changed-red "Method return type changed" +[Method return type generics changed]: https://img.shields.io/badge/Method_return_type_generics_changed-orange "Method return type generics changed" +[No changes]: https://img.shields.io/badge/No_changes-green "No changes" +[Not serializable]: https://img.shields.io/badge/Not_serializable-green "Not serializable" +[Superclass added]: https://img.shields.io/badge/Superclass_added-orange "Superclass added" +[Superclass modified]: https://img.shields.io/badge/Incompatible-red "Superclass modified" +[`AbstractCollection`]: # "java.util.AbstractCollection" +[`AbstractExecutorService`]: # "java.util.concurrent.AbstractExecutorService" +[`AbstractFuture`]: # "com.google.common.util.concurrent.AbstractFuture" +[`AbstractMap`]: # "java.util.AbstractMap" +[`AbstractMultimap`]: # "com.google.common.collect.AbstractMultimap" +[`AbstractRangeSet`]: # "com.google.common.collect.AbstractRangeSet" +[`AsyncFunction`]: # "com.google.common.util.concurrent.AsyncFunction" +[`AsyncFunction`]: # "com.google.common.util.concurrent.AsyncFunction" +[`B extends Object`]: # "B extends java.lang.Object" +[`BiMap`]: # "com.google.common.collect.BiMap" +[`BloomFilter`]: # "com.google.common.hash.BloomFilter" +[`Boolean`]: # "java.lang.Boolean" +[`Builder`]: # "com.google.common.collect.ImmutableSortedMultiset$Builder" +[`Builder`]: # "com.google.common.collect.ImmutableMap$Builder" +[`Callable`]: # "java.util.concurrent.Callable" +[`CharMatcher`]: # "com.google.common.base.CharMatcher" +[`CharSequence`]: # "java.lang.CharSequence" +[`CheckForNull`]: # "javax.annotation.CheckForNull" +[`CheckReturnValue`]: # "javax.annotation.CheckReturnValue" +[`CheckedFuture`]: # "com.google.common.util.concurrent.CheckedFuture" +[`Class`]: # "java.lang.Class" +[`Class`]: # "java.lang.Class" +[`Class`]: # "java.lang.Class" +[`Class`]: # "java.lang.Class" +[`Collection`]: # "java.util.Collection" +[`Collection`]: # "java.util.Collection" +[`Comparable`]: # "java.lang.Comparable" +[`Comparable`]: # "java.lang.Comparable" +[`Comparator`]: # "java.util.Comparator" +[`Comparator`]: # "java.util.Comparator" +[`Comparator`]: # "java.util.Comparator" +[`Comparator`]: # "java.util.Comparator" +[`ComparisonChain`]: # "com.google.common.collect.ComparisonChain" +[`Deprecated`]: # "java.lang.Deprecated" +[`Double`]: # "java.lang.Double" +[`E extends Comparable`]: # "E extends java.lang.Comparable" +[`E extends Comparable`]: # "E extends java.lang.Comparable" +[`E extends Object`]: # "E extends java.lang.Object" +[`Entry`]: # "java.util.Map$Entry" +[`Enum`]: # "java.lang.Enum>" +[`EventBus`]: # "com.google.common.eventbus.EventBus" +[`Exception`]: # "java.lang.Exception" +[`Executor`]: # "java.util.concurrent.Executor" +[`F extends Object`]: # "F extends java.lang.Object" +[`FilterInputStream`]: # "java.io.FilterInputStream" +[`FilterOutputStream`]: # "java.io.FilterOutputStream" +[`Float`]: # "java.lang.Float" +[`FluentIterable`]: # "com.google.common.collect.FluentIterable" +[`FluentIterable`]: # "com.google.common.collect.FluentIterable" +[`ForwardingMap`]: # "com.google.common.collect.ForwardingMap" +[`Function>`]: # "com.google.common.base.Function>" +[`Function`]: # "com.google.common.base.Function" +[`Function`]: # "com.google.common.base.Function" +[`Function`]: # "com.google.common.base.Function" +[`Function`]: # "com.google.common.base.Function" +[`Function`]: # "com.google.common.base.Function" +[`Function`]: # "com.google.common.base.Function" +[`Function`]: # "com.google.common.base.Function" +[`Funnel`]: # "com.google.common.hash.Funnel" +[`Funnel`]: # "com.google.common.hash.Funnel" +[`Future`]: # "java.util.concurrent.Future" +[`Future`]: # "java.util.concurrent.Future" +[`Future`]: # "java.util.concurrent.Future" +[`FutureFallback`]: # "com.google.common.util.concurrent.FutureFallback" +[`GenericMapMaker`]: # "com.google.common.collect.GenericMapMaker" +[`GwtFuturesCatchingSpecialization`]: # "com.google.common.util.concurrent.GwtFuturesCatchingSpecialization" +[`HashCode`]: # "com.google.common.hash.HashCode" +[`HashFunction...`]: # "com.google.common.hash.HashFunction..." +[`HashFunction`]: # "com.google.common.hash.HashFunction" +[`I extends Object`]: # "I extends java.lang.Object" +[`IOException`]: # "java.io.IOException" +[`ImmutableBiMap`]: # "com.google.common.collect.ImmutableBiMap" +[`ImmutableClassToInstanceMap`]: # "com.google.common.collect.ImmutableClassToInstanceMap" +[`ImmutableCollection`]: # "com.google.common.collect.ImmutableCollection" +[`ImmutableCollection`]: # "com.google.common.collect.ImmutableCollection" +[`ImmutableList`]: # "com.google.common.collect.ImmutableList" +[`ImmutableList>`]: # "com.google.common.collect.ImmutableList>" +[`ImmutableListMultimap`]: # "com.google.common.collect.ImmutableListMultimap" +[`ImmutableListMultimap`]: # "com.google.common.collect.ImmutableListMultimap" +[`ImmutableMap`]: # "com.google.common.collect.ImmutableMap" +[`ImmutableMap`]: # "com.google.common.collect.ImmutableMap" +[`ImmutableMap`]: # "com.google.common.collect.ImmutableMap" +[`ImmutableMap, V>`]: # "com.google.common.collect.ImmutableMap, V>" +[`ImmutableMultimap`]: # "com.google.common.collect.ImmutableMultimap" +[`ImmutableMultiset`]: # "com.google.common.collect.ImmutableMultiset" +[`ImmutableSet`]: # "com.google.common.collect.ImmutableSet" +[`ImmutableSet>`]: # "com.google.common.collect.ImmutableSet>" +[`ImmutableSetMultimap`]: # "com.google.common.collect.ImmutableSetMultimap" +[`ImmutableSortedMap`]: # "com.google.common.collect.ImmutableSortedMap" +[`ImmutableSortedMapFauxverideShim`]: # "com.google.common.collect.ImmutableSortedMapFauxverideShim" +[`ImmutableSortedSet`]: # "com.google.common.collect.ImmutableSortedSet" +[`ImmutableSortedSet`]: # "com.google.common.collect.ImmutableSortedSet" +[`ImmutableSortedSetFauxverideShim`]: # "com.google.common.collect.ImmutableSortedSetFauxverideShim" +[`ImmutableSorted…etFauxverideShim`]: # "com.google.common.collect.ImmutableSortedMultisetFauxverideShim" +[`InputStream`]: # "java.io.InputStream" +[`Integer`]: # "java.lang.Integer" +[`Iterable>`]: # "java.lang.Iterable>" +[`Iterable>`]: # "java.lang.Iterable>" +[`Iterable>`]: # "java.lang.Iterable>" +[`Iterable>`]: # "java.lang.Iterable>" +[`Iterable`]: # "java.lang.Iterable" +[`Iterable`]: # "java.lang.Iterable" +[`Iterable`]: # "java.lang.Iterable" +[`Iterable`]: # "java.lang.Iterable" +[`Iterable`]: # "java.lang.Iterable" +[`Iterable`]: # "java.lang.Iterable" +[`Iterator>`]: # "java.util.Iterator>" +[`Iterator`]: # "java.util.Iterator" +[`Iterator`]: # "java.util.Iterator" +[`IteratorBasedAbstractMap`]: # "com.google.common.collect.Maps$IteratorBasedAbstractMap" +[`Joiner`]: # "com.google.common.base.Joiner" +[`K extends Object`]: # "K extends java.lang.Object" +[`LinkedHashMap`]: # "java.util.LinkedHashMap" +[`List...`]: # "java.util.List..." +[`List>`]: # "java.util.List>" +[`List`]: # "java.util.List" +[`List>`]: # "java.util.List>" +[`List`]: # "java.util.List" +[`List`]: # "java.util.List" +[`List`]: # "java.util.List" +[`List`]: # "java.util.List" +[`ListMultimap`]: # "com.google.common.collect.ListMultimap" +[`ListenableFuture...`]: # "com.google.common.util.concurrent.ListenableFuture..." +[`ListenableFuture>`]: # "com.google.common.util.concurrent.ListenableFuture>" +[`ListenableFuture`]: # "com.google.common.util.concurrent.ListenableFuture" +[`ListenableFuture`]: # "com.google.common.util.concurrent.ListenableFuture" +[`ListenableFuture>`]: # "com.google.common.util.concurrent.ListenableFuture>" +[`ListenableFuture`]: # "com.google.common.util.concurrent.ListenableFuture" +[`ListenableFuture`]: # "com.google.common.util.concurrent.ListenableFuture" +[`ListenableFutureTask`]: # "com.google.common.util.concurrent.ListenableFutureTask" +[`Long`]: # "java.lang.Long" +[`Map`]: # "java.util.Map" +[`Map`]: # "java.util.Map" +[`Map`]: # "java.util.Map" +[`Map, V>`]: # "java.util.Map, V>" +[`Map`]: # "java.util.Map" +[`MapMaker`]: # "com.google.common.collect.MapMaker" +[`MediaType`]: # "com.google.common.net.MediaType" +[`Multimap`]: # "com.google.common.collect.Multimap" +[`Multiset`]: # "com.google.common.collect.Multiset" +[`Multiset`]: # "com.google.common.collect.Multiset" +[`NavigableMap`]: # "java.util.NavigableMap" +[`NavigableSet`]: # "java.util.NavigableSet" +[`NoSuchElementException`]: # "java.util.NoSuchElementException" +[`Nullable`]: # "javax.annotation.Nullable" +[`Number`]: # "java.lang.Number" +[`O extends Object`]: # "O extends java.lang.Object" +[`Object...`]: # "java.lang.Object..." +[`Object`]: # "java.lang.Object" +[`Optional`]: # "com.google.common.base.Optional" +[`Optional`]: # "com.google.common.base.Optional" +[`OutputStream`]: # "java.io.OutputStream" +[`Pattern`]: # "java.util.regex.Pattern" +[`Predicate`]: # "com.google.common.base.Predicate" +[`Predicate>`]: # "com.google.common.base.Predicate>" +[`Predicate`]: # "com.google.common.base.Predicate" +[`Predicate`]: # "com.google.common.base.Predicate" +[`Predicate`]: # "com.google.common.base.Predicate" +[`RangeMap`]: # "com.google.common.collect.RangeMap" +[`RangeSet`]: # "com.google.common.collect.RangeSet" +[`Reader`]: # "java.io.Reader" +[`RemovalCause`]: # "com.google.common.cache.RemovalCause" +[`RemovalNotification`]: # "com.google.common.cache.RemovalNotification" +[`RunnableFuture`]: # "java.util.concurrent.RunnableFuture" +[`Runnable`]: # "java.lang.Runnable" +[`RuntimeException`]: # "java.lang.RuntimeException" +[`SafeVarargs`]: # "java.lang.SafeVarargs" +[`ScheduledExecutorService`]: # "java.util.concurrent.ScheduledExecutorService" +[`Serializable`]: # "java.io.Serializable" +[`Set`]: # "java.util.Set" +[`Set>`]: # "java.util.Set>" +[`Set>`]: # "java.util.Set>" +[`SetMultimap`]: # "com.google.common.collect.SetMultimap" +[`Set`]: # "java.util.Set" +[`SortedMap`]: # "java.util.SortedMap" +[`SortedSet`]: # "java.util.SortedSet" +[`Splitter`]: # "com.google.common.base.Splitter" +[`Stopwatch`]: # "com.google.common.base.Stopwatch" +[`String`]: # "java.lang.String" +[`T extends Object`]: # "T extends java.lang.Object" +[`Throwable`]: # "java.lang.Throwable" +[`Ticker`]: # "com.google.common.base.Ticker" +[`TimeUnit`]: # "java.util.concurrent.TimeUnit" +[`ToStringHelper`]: # "com.google.common.base.MoreObjects$ToStringHelper" +[`TrustedFuture`]: # "com.google.common.util.concurrent.AbstractFuture$TrustedFuture" +[`TypeCapture`]: # "com.google.common.reflect.TypeCapture" +[`TypeToken`]: # "com.google.common.reflect.TypeToken" +[`Type`]: # "java.lang.reflect.Type" +[`URL`]: # "java.net.URL" +[`UnmodifiableIterator`]: # "com.google.common.collect.UnmodifiableIterator" +[`UnsignedInteger`]: # "com.google.common.primitives.UnsignedInteger" +[`UnsignedLong`]: # "com.google.common.primitives.UnsignedLong" +[`UnsupportedOperationException`]: # "java.lang.UnsupportedOperationException" +[`V extends Object`]: # "V extends java.lang.Object" +[`Writer`]: # "java.io.Writer" +[`X extends Exception`]: # "X extends java.lang.Exception" +[`X extends Throwable`]: # "X extends java.lang.Throwable" +[com.google.common.base.Ascii]: #user-content-com.google.common.base.ascii +[com.google.common.base.CaseFormat]: #user-content-com.google.common.base.caseformat +[com.google.common.base.CharMatcher]: #user-content-com.google.common.base.charmatcher +[com.google.common.base.Defaults]: #user-content-com.google.common.base.defaults +[com.google.common.base.Enums]: #user-content-com.google.common.base.enums +[com.google.common.base.Equivalence]: #user-content-com.google.common.base.equivalence +[com.google.common.base.Functions]: #user-content-com.google.common.base.functions +[com.google.common.base.Joiner]: #user-content-com.google.common.base.joiner +[com.google.common.base.Joiner$MapJoiner]: #user-content-com.google.common.base.joiner$mapjoiner +[com.google.common.base.MoreObjects]: #user-content-com.google.common.base.moreobjects +[com.google.common.base.MoreObjects$ToStringHelper]: #user-content-com.google.common.base.moreobjects$tostringhelper +[com.google.common.base.Objects]: #user-content-com.google.common.base.objects +[com.google.common.base.Optional]: #user-content-com.google.common.base.optional +[com.google.common.base.Predicates]: #user-content-com.google.common.base.predicates +[com.google.common.base.Splitter]: #user-content-com.google.common.base.splitter +[com.google.common.base.Splitter$MapSplitter]: #user-content-com.google.common.base.splitter$mapsplitter +[com.google.common.base.StandardSystemProperty]: #user-content-com.google.common.base.standardsystemproperty +[com.google.common.base.Stopwatch]: #user-content-com.google.common.base.stopwatch +[com.google.common.base.Strings]: #user-content-com.google.common.base.strings +[com.google.common.base.Suppliers]: #user-content-com.google.common.base.suppliers +[com.google.common.base.Throwables]: #user-content-com.google.common.base.throwables +[com.google.common.base.Ticker]: #user-content-com.google.common.base.ticker +[com.google.common.base.Utf8]: #user-content-com.google.common.base.utf8 +[com.google.common.base.VerifyException]: #user-content-com.google.common.base.verifyexception +[com.google.common.cache.CacheLoader$UnsupportedLoadingOperationException]: #user-content-com.google.common.cache.cacheloader$unsupportedloadingoperationexception +[com.google.common.cache.RemovalNotification]: #user-content-com.google.common.cache.removalnotification +[com.google.common.collect.BiMap]: #user-content-com.google.common.collect.bimap +[com.google.common.collect.Collections2]: #user-content-com.google.common.collect.collections2 +[com.google.common.collect.ComparisonChain]: #user-content-com.google.common.collect.comparisonchain +[com.google.common.collect.FluentIterable]: #user-content-com.google.common.collect.fluentiterable +[com.google.common.collect.HashBiMap]: #user-content-com.google.common.collect.hashbimap +[com.google.common.collect.ImmutableBiMap]: #user-content-com.google.common.collect.immutablebimap +[com.google.common.collect.ImmutableBiMap$Builder]: #user-content-com.google.common.collect.immutablebimap$builder +[com.google.common.collect.ImmutableClassToInstanceMap]: #user-content-com.google.common.collect.immutableclasstoinstancemap +[com.google.common.collect.ImmutableCollection]: #user-content-com.google.common.collect.immutablecollection +[com.google.common.collect.ImmutableList]: #user-content-com.google.common.collect.immutablelist +[com.google.common.collect.ImmutableListMultimap]: #user-content-com.google.common.collect.immutablelistmultimap +[com.google.common.collect.ImmutableListMultimap$Builder]: #user-content-com.google.common.collect.immutablelistmultimap$builder +[com.google.common.collect.ImmutableMap]: #user-content-com.google.common.collect.immutablemap +[com.google.common.collect.ImmutableMap$Builder]: #user-content-com.google.common.collect.immutablemap$builder +[com.google.common.collect.ImmutableMultimap]: #user-content-com.google.common.collect.immutablemultimap +[com.google.common.collect.ImmutableMultimap$Builder]: #user-content-com.google.common.collect.immutablemultimap$builder +[com.google.common.collect.ImmutableMultiset]: #user-content-com.google.common.collect.immutablemultiset +[com.google.common.collect.ImmutableRangeMap]: #user-content-com.google.common.collect.immutablerangemap +[com.google.common.collect.ImmutableRangeSet]: #user-content-com.google.common.collect.immutablerangeset +[com.google.common.collect.ImmutableSetMultimap]: #user-content-com.google.common.collect.immutablesetmultimap +[com.google.common.collect.ImmutableSetMultimap$Builder]: #user-content-com.google.common.collect.immutablesetmultimap$builder +[com.google.common.collect.ImmutableSortedMap]: #user-content-com.google.common.collect.immutablesortedmap +[com.google.common.collect.ImmutableSortedMap$Builder]: #user-content-com.google.common.collect.immutablesortedmap$builder +[com.google.common.collect.ImmutableSortedMultiset]: #user-content-com.google.common.collect.immutablesortedmultiset +[com.google.common.collect.ImmutableSortedSet]: #user-content-com.google.common.collect.immutablesortedset +[com.google.common.collect.Iterables]: #user-content-com.google.common.collect.iterables +[com.google.common.collect.Iterators]: #user-content-com.google.common.collect.iterators +[com.google.common.collect.Lists]: #user-content-com.google.common.collect.lists +[com.google.common.collect.MapConstraint]: #user-content-com.google.common.collect.mapconstraint +[com.google.common.collect.MapConstraints]: #user-content-com.google.common.collect.mapconstraints +[com.google.common.collect.MapMaker]: #user-content-com.google.common.collect.mapmaker +[com.google.common.collect.Maps]: #user-content-com.google.common.collect.maps +[com.google.common.collect.MultimapBuilder]: #user-content-com.google.common.collect.multimapbuilder +[com.google.common.collect.Multimaps]: #user-content-com.google.common.collect.multimaps +[com.google.common.collect.Multisets]: #user-content-com.google.common.collect.multisets +[com.google.common.collect.RangeMap]: #user-content-com.google.common.collect.rangemap +[com.google.common.collect.RangeSet]: #user-content-com.google.common.collect.rangeset +[com.google.common.collect.Sets]: #user-content-com.google.common.collect.sets +[com.google.common.collect.Table]: #user-content-com.google.common.collect.table +[com.google.common.collect.Table$Cell]: #user-content-com.google.common.collect.table$cell +[com.google.common.collect.TreeRangeMap]: #user-content-com.google.common.collect.treerangemap +[com.google.common.collect.TreeRangeSet]: #user-content-com.google.common.collect.treerangeset +[com.google.common.eventbus.AsyncEventBus]: #user-content-com.google.common.eventbus.asynceventbus +[com.google.common.eventbus.DeadEvent]: #user-content-com.google.common.eventbus.deadevent +[com.google.common.eventbus.EventBus]: #user-content-com.google.common.eventbus.eventbus +[com.google.common.hash.BloomFilter]: #user-content-com.google.common.hash.bloomfilter +[com.google.common.hash.Funnels]: #user-content-com.google.common.hash.funnels +[com.google.common.hash.HashCode]: #user-content-com.google.common.hash.hashcode +[com.google.common.hash.Hasher]: #user-content-com.google.common.hash.hasher +[com.google.common.hash.Hashing]: #user-content-com.google.common.hash.hashing +[com.google.common.hash.HashingInputStream]: #user-content-com.google.common.hash.hashinginputstream +[com.google.common.hash.HashingOutputStream]: #user-content-com.google.common.hash.hashingoutputstream +[com.google.common.io.BaseEncoding]: #user-content-com.google.common.io.baseencoding +[com.google.common.io.ByteSource]: #user-content-com.google.common.io.bytesource +[com.google.common.io.CharSource]: #user-content-com.google.common.io.charsource +[com.google.common.net.HttpHeaders]: #user-content-com.google.common.net.httpheaders +[com.google.common.net.MediaType]: #user-content-com.google.common.net.mediatype +[com.google.common.primitives.Booleans]: #user-content-com.google.common.primitives.booleans +[com.google.common.primitives.Bytes]: #user-content-com.google.common.primitives.bytes +[com.google.common.primitives.Chars]: #user-content-com.google.common.primitives.chars +[com.google.common.primitives.Doubles]: #user-content-com.google.common.primitives.doubles +[com.google.common.primitives.Floats]: #user-content-com.google.common.primitives.floats +[com.google.common.primitives.Ints]: #user-content-com.google.common.primitives.ints +[com.google.common.primitives.Longs]: #user-content-com.google.common.primitives.longs +[com.google.common.primitives.Primitives]: #user-content-com.google.common.primitives.primitives +[com.google.common.primitives.Shorts]: #user-content-com.google.common.primitives.shorts +[com.google.common.primitives.SignedBytes]: #user-content-com.google.common.primitives.signedbytes +[com.google.common.primitives.UnsignedBytes]: #user-content-com.google.common.primitives.unsignedbytes +[com.google.common.primitives.UnsignedInteger]: #user-content-com.google.common.primitives.unsignedinteger +[com.google.common.primitives.UnsignedInts]: #user-content-com.google.common.primitives.unsignedints +[com.google.common.primitives.UnsignedLong]: #user-content-com.google.common.primitives.unsignedlong +[com.google.common.primitives.UnsignedLongs]: #user-content-com.google.common.primitives.unsignedlongs +[com.google.common.reflect.ClassPath$ResourceInfo]: #user-content-com.google.common.reflect.classpath$resourceinfo +[com.google.common.reflect.TypeToken]: #user-content-com.google.common.reflect.typetoken +[com.google.common.util.concurrent.AbstractFuture]: #user-content-com.google.common.util.concurrent.abstractfuture +[com.google.common.util.concurrent.AbstractListeningExecutorService]: #user-content-com.google.common.util.concurrent.abstractlisteningexecutorservice +[com.google.common.util.concurrent.FutureFallback]: #user-content-com.google.common.util.concurrent.futurefallback +[com.google.common.util.concurrent.Futures]: #user-content-com.google.common.util.concurrent.futures +[com.google.common.util.concurrent.SettableFuture]: #user-content-com.google.common.util.concurrent.settablefuture diff --git a/doc/japicmp_guava_markdown.png b/doc/japicmp_guava_markdown.png new file mode 100644 index 000000000..c7fc15aed Binary files /dev/null and b/doc/japicmp_guava_markdown.png differ diff --git a/japicmp-ant-task/src/main/java/japicmp/ant/JApiCmpTask.java b/japicmp-ant-task/src/main/java/japicmp/ant/JApiCmpTask.java index b44f40076..8672c99d3 100644 --- a/japicmp-ant-task/src/main/java/japicmp/ant/JApiCmpTask.java +++ b/japicmp-ant-task/src/main/java/japicmp/ant/JApiCmpTask.java @@ -9,6 +9,7 @@ import japicmp.output.html.HtmlOutputGenerator; import japicmp.output.html.HtmlOutputGeneratorOptions; import japicmp.output.incompatible.IncompatibleErrorOutput; +import japicmp.output.markdown.MarkdownOutputGenerator; import japicmp.output.semver.SemverOut; import japicmp.output.stdout.StdoutOutputGenerator; import japicmp.output.xml.XmlOutput; @@ -38,6 +39,7 @@ public class JApiCmpTask extends Task { private boolean includeSynthetic = false; private boolean noAnnotations = false; private boolean semanticVersioning = false; + private boolean markdown = false; private boolean reportOnlyFilename = false; private boolean reportOnlySummary = false; private boolean ignoreMissingClasses = false; @@ -46,6 +48,7 @@ public class JApiCmpTask extends Task { private final List ignoreMissingClassesByRegularExpressions = new ArrayList<>(); private String accessModifier = "protected"; private String semanticVersionProperty; + private String markdownProperty; private String oldJar; private String newJar; private Path oldClassPath; @@ -88,6 +91,15 @@ public void setSemVerProperty(String semverProperty) { semanticVersionProperty = semverProperty; } + public void setMarkdown(String markdown) { + this.markdown = Project.toBoolean(markdown); + } + + public void setMarkdownProperty(String mdProperty) { + markdown = Boolean.TRUE; + markdownProperty = mdProperty; + } + public void setReportOnlyFilename(String reportOnlyFilename) { this.reportOnlyFilename = Project.toBoolean(reportOnlyFilename); } @@ -284,6 +296,14 @@ private void generateOutput(Options options, List jApiClasses, JarArc } log(semver); return; + } else if (markdown) { + MarkdownOutputGenerator markdownOutputGenerator = new MarkdownOutputGenerator(options, jApiClasses); + String md = markdownOutputGenerator.generate(); + if (markdownProperty != null) { + getProject().setProperty(markdownProperty, md); + } + log(md); + return; } if (!options.getXmlOutputFile().isPresent() && !options.getHtmlOutputFile().isPresent()) { diff --git a/japicmp-maven-plugin/src/main/java/japicmp/maven/JApiCmpMojo.java b/japicmp-maven-plugin/src/main/java/japicmp/maven/JApiCmpMojo.java index 6b892fc43..1396962f8 100644 --- a/japicmp-maven-plugin/src/main/java/japicmp/maven/JApiCmpMojo.java +++ b/japicmp-maven-plugin/src/main/java/japicmp/maven/JApiCmpMojo.java @@ -15,6 +15,8 @@ import japicmp.output.html.HtmlOutputGenerator; import japicmp.output.html.HtmlOutputGeneratorOptions; import japicmp.output.incompatible.IncompatibleErrorOutput; +import japicmp.output.markdown.MarkdownOutputGenerator; +import japicmp.output.markdown.config.MarkdownOptions; import japicmp.output.semver.SemverOut; import japicmp.output.stdout.StdoutOutputGenerator; import japicmp.output.xml.XmlOutput; @@ -77,6 +79,8 @@ public class JApiCmpMojo extends AbstractMojo { private boolean skip; @org.apache.maven.plugins.annotations.Parameter(property = "japicmp.skip", defaultValue = "false") private boolean skipExec; + @org.apache.maven.plugins.annotations.Parameter(property = "japicmp.skipMarkdownReport", required = false) + private boolean skipMarkdownReport; @org.apache.maven.plugins.annotations.Parameter(property = "japicmp.skipXmlReport", required = false) private boolean skipXmlReport; @org.apache.maven.plugins.annotations.Parameter(property = "japicmp.skipHtmlReport", required = false) @@ -148,6 +152,9 @@ Optional executeWithParameters(PluginParameters pluginParameters, Ma SemverOut semverOut = new SemverOut(options, jApiClasses); String semanticVersioningInformation = semverOut.generate(); generateDiffOutput(mavenParameters, pluginParameters, options, jApiClasses, jApiCmpBuildDir, semanticVersioningInformation); + if (!skipMarkdownReport(pluginParameters)) { + generateMarkdownOutput(mavenParameters, pluginParameters, options, jApiClasses, jApiCmpBuildDir); + } if (!skipXmlReport(pluginParameters)) { XmlOutput xmlOutput = generateXmlOutput(jApiClasses, jApiCmpBuildDir, options, mavenParameters, pluginParameters, semanticVersioningInformation); if (pluginParameters.isWriteToFiles()) { @@ -576,6 +583,18 @@ private void generateDiffOutput(MavenParameters mavenParameters, PluginParameter } } + private void generateMarkdownOutput(MavenParameters mavenParameters, PluginParameters pluginParameters, Options options, + List jApiClasses, File jApiCmpBuildDir) throws IOException, MojoFailureException { + MarkdownOptions mdOptions = MarkdownOptions.newDefault(options); + if (pluginParameters.getParameterParam() != null && pluginParameters.getParameterParam().getMarkdownTitle() != null) { + mdOptions.title.report = pluginParameters.getParameterParam().getMarkdownTitle(); + } + MarkdownOutputGenerator mdOut = new MarkdownOutputGenerator(mdOptions, jApiClasses); + String markdown = mdOut.generate(); + File output = new File(jApiCmpBuildDir.getCanonicalPath() + File.separator + createFilename(mavenParameters) + ".md"); + writeToFile(markdown, output); + } + private XmlOutput generateXmlOutput(List jApiClasses, File jApiCmpBuildDir, Options options, MavenParameters mavenParameters, PluginParameters pluginParameters, String semanticVersioningInformation) throws IOException { String filename = createFilename(mavenParameters); @@ -621,6 +640,14 @@ private boolean skipXmlReport(PluginParameters pluginParameters) { return skipReport || this.skipXmlReport; } + private boolean skipMarkdownReport(PluginParameters pluginParameters) { + boolean skipReport = false; + if (pluginParameters.getParameterParam() != null) { + skipReport = pluginParameters.getParameterParam().getSkipMarkdownReport(); + } + return skipReport || this.skipMarkdownReport; + } + private String createFilename(MavenParameters mavenParameters) { String filename = "japicmp"; String executionId = mavenParameters.getMojoExecution().getExecutionId(); diff --git a/japicmp-maven-plugin/src/main/java/japicmp/maven/Parameter.java b/japicmp-maven-plugin/src/main/java/japicmp/maven/Parameter.java index 8aa3f0f19..51bb6b1ec 100644 --- a/japicmp-maven-plugin/src/main/java/japicmp/maven/Parameter.java +++ b/japicmp-maven-plugin/src/main/java/japicmp/maven/Parameter.java @@ -23,6 +23,8 @@ public class Parameter { @org.apache.maven.plugins.annotations.Parameter(required = false) private String htmlTitle; @org.apache.maven.plugins.annotations.Parameter(required = false) + private String markdownTitle; + @org.apache.maven.plugins.annotations.Parameter(required = false) private boolean noAnnotations; @org.apache.maven.plugins.annotations.Parameter(required = false) private String ignoreNonResolvableArtifacts; @@ -35,6 +37,8 @@ public class Parameter { @org.apache.maven.plugins.annotations.Parameter(required = false) private boolean skipXmlReport; @org.apache.maven.plugins.annotations.Parameter(required = false) + private boolean skipMarkdownReport; + @org.apache.maven.plugins.annotations.Parameter(required = false) private boolean skipDiffReport; @org.apache.maven.plugins.annotations.Parameter(required = false) private boolean ignoreMissingOldVersion; @@ -221,6 +225,14 @@ public void setHtmlTitle(String htmlTitle) { this.htmlTitle = htmlTitle; } + public String getMarkdownTitle() { + return markdownTitle; + } + + public void setMarkdownTitle(String markdownTitle) { + this.markdownTitle = markdownTitle; + } + public String getIgnoreNonResolvableArtifacts() { return ignoreNonResolvableArtifacts; } @@ -277,6 +289,14 @@ public void setSkipXmlReport(boolean skipXmlReport) { this.skipXmlReport = skipXmlReport; } + public boolean getSkipMarkdownReport() { + return skipMarkdownReport; + } + + public void setSkipMarkdownReport(boolean skipMarkdownReport) { + this.skipMarkdownReport = skipMarkdownReport; + } + public boolean isSkipDiffReport() { return skipDiffReport; } diff --git a/japicmp-testbase/japicmp-test-maven-plugin/pom.xml b/japicmp-testbase/japicmp-test-maven-plugin/pom.xml index 0df80b09c..16dc67134 100644 --- a/japicmp-testbase/japicmp-test-maven-plugin/pom.xml +++ b/japicmp-testbase/japicmp-test-maven-plugin/pom.xml @@ -108,6 +108,7 @@ true ${project.basedir}/src/main/resources/css/stylesheet.css Test-Title + Test-Markdown-Title @@ -190,6 +191,7 @@ true true true + true diff --git a/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITClassFileFormatVersion.java b/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITClassFileFormatVersion.java index 4da3a7335..4ff700387 100644 --- a/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITClassFileFormatVersion.java +++ b/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITClassFileFormatVersion.java @@ -38,6 +38,24 @@ public void testClassFileFormatVersionIsPresent() throws IOException { } } + @Test + public void testMarkdownReportDiffClassFileFormatVersionIsPresent() throws IOException { + Path path = Paths.get(System.getProperty("user.dir"), "target", "japicmp", "class-file-format-version.md"); + if (!Files.exists(path)) { + return; //in JDK 1.7 case + } + assertThat(Files.exists(path), is(true)); + List lines = Files.readAllLines(path, StandardCharsets.UTF_8); + boolean found = false; + for (String line : lines) { + if (line.contains("~~JDK 6~~ → **JDK 8**")) { + found = true; + break; + } + } + assertThat(found, is(true)); + } + @Test public void testStoutDiffClassFileFormatVersionIsPresent() throws IOException { Path path = Paths.get(System.getProperty("user.dir"), "target", "japicmp", "class-file-format-version.diff"); diff --git a/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITMarkdownTitle.java b/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITMarkdownTitle.java new file mode 100644 index 000000000..c3af25cef --- /dev/null +++ b/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITMarkdownTitle.java @@ -0,0 +1,30 @@ +package japicmp.test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import org.junit.Test; + +public class ITMarkdownTitle { + + @Test + public void testMarkdownTitle() throws IOException { + Path markdownPath = Paths.get(System.getProperty("user.dir"), "target", "japicmp", "single-version.md"); + assertThat(Files.exists(markdownPath), is(true)); + List lines = Files.readAllLines(markdownPath, StandardCharsets.UTF_8); + boolean found = false; + for (String line : lines) { + if (line.equals("# Test-Markdown-Title")) { + found = true; + break; + } + } + assertThat(found, is(true)); + } +} diff --git a/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITModuleExcluded.java b/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITModuleExcluded.java index d565dc30a..194f340fb 100644 --- a/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITModuleExcluded.java +++ b/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITModuleExcluded.java @@ -21,6 +21,11 @@ public void testHtmlReportNotGenerated() throws IOException { assertThat(Files.exists(Paths.get(System.getProperty("user.dir"), "target", "japicmp", "ignore-module.xml")), is(false)); } + @Test + public void testMarkdownReportGenerated() throws IOException { + assertThat(Files.exists(Paths.get(System.getProperty("user.dir"), "target", "japicmp", "ignore-module.md")), is(false)); + } + @Test public void testDiffReportGenerated() throws IOException { assertThat(Files.exists(Paths.get(System.getProperty("user.dir"), "target", "japicmp", "ignore-module.diff")), is(false)); diff --git a/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITMultipleExecutions.java b/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITMultipleExecutions.java index a54441f6a..d829ff46b 100644 --- a/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITMultipleExecutions.java +++ b/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITMultipleExecutions.java @@ -14,9 +14,11 @@ public class ITMultipleExecutions { public void testThatXmlAndHtmlFilesAreWritten() { assertThat(Files.exists(Paths.get(System.getProperty("user.dir"), "target", "japicmp", "multiple-versions.html")), is(true)); assertThat(Files.exists(Paths.get(System.getProperty("user.dir"), "target", "japicmp", "multiple-versions.xml")), is(true)); + assertThat(Files.exists(Paths.get(System.getProperty("user.dir"), "target", "japicmp", "multiple-versions.md")), is(true)); assertThat(Files.exists(Paths.get(System.getProperty("user.dir"), "target", "japicmp", "multiple-versions.diff")), is(true)); assertThat(Files.exists(Paths.get(System.getProperty("user.dir"), "target", "japicmp", "single-version.html")), is(true)); assertThat(Files.exists(Paths.get(System.getProperty("user.dir"), "target", "japicmp", "single-version.xml")), is(true)); + assertThat(Files.exists(Paths.get(System.getProperty("user.dir"), "target", "japicmp", "single-version.md")), is(true)); assertThat(Files.exists(Paths.get(System.getProperty("user.dir"), "target", "japicmp", "single-version.diff")), is(true)); } } diff --git a/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITNoReports.java b/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITNoReports.java index 6cc8ebc8b..5504fecc6 100644 --- a/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITNoReports.java +++ b/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITNoReports.java @@ -21,6 +21,11 @@ public void testHtmlReportNotGenerated() throws IOException { assertThat(Files.exists(Paths.get(System.getProperty("user.dir"), "target", "japicmp", "no-reports.xml")), is(false)); } + @Test + public void testMarkdownReportNotGenerated() throws IOException { + assertThat(Files.exists(Paths.get(System.getProperty("user.dir"), "target", "japicmp", "no-reports.md")), is(false)); + } + @Test public void testDiffReportGenerated() throws IOException { assertThat(Files.exists(Paths.get(System.getProperty("user.dir"), "target", "japicmp", "no-reports.diff")), is(true)); diff --git a/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITSkip.java b/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITSkip.java index bb44c3a09..007337f0b 100644 --- a/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITSkip.java +++ b/japicmp-testbase/japicmp-test-maven-plugin/src/test/java/japicmp/test/ITSkip.java @@ -21,6 +21,11 @@ public void testHtmlReportNotGenerated() throws IOException { assertThat(Files.exists(Paths.get(System.getProperty("user.dir"), "target", "japicmp", "skip.xml")), is(false)); } + @Test + public void testMarkdownReportGenerated() throws IOException { + assertThat(Files.exists(Paths.get(System.getProperty("user.dir"), "target", "japicmp", "skip.md")), is(false)); + } + @Test public void testDiffReportGenerated() throws IOException { assertThat(Files.exists(Paths.get(System.getProperty("user.dir"), "target", "japicmp", "skip.diff")), is(false)); diff --git a/japicmp/src/main/java/japicmp/cli/CliParser.java b/japicmp/src/main/java/japicmp/cli/CliParser.java index b0c05216b..7afcfde0e 100644 --- a/japicmp/src/main/java/japicmp/cli/CliParser.java +++ b/japicmp/src/main/java/japicmp/cli/CliParser.java @@ -64,6 +64,8 @@ public Options parse(String[] args) throws IllegalArgumentException { options.setHtmlOutputFile(Optional.fromNullable(pathToHtmlOutputFile)); } else if ("-s".equals(arg) || "--semantic-versioning".equals(arg)) { options.setSemanticVersioning(true); + } else if ("--markdown".equals(arg)) { + options.setMarkdown(true); } else if ("--include-synthetic".equals(arg)) { options.setIncludeSynthetic(true); } else if (IGNORE_MISSING_CLASSES.equals(arg)) { @@ -128,6 +130,7 @@ public static void printHelp() { " [--old-classpath ]\n" + " [--report-only-filename] [--report-only-summary]\n" + " [(-s | --semantic-versioning)]\n" + + " [--markdown]\n" + " [(-x | --xml-file )]\n" + " [--error-on-binary-incompatibility]\n" + " [--error-on-source-incompatibility]\n" + @@ -215,6 +218,9 @@ public static void printHelp() { " -s, --semantic-versioning\n" + " Tells you which part of the version to increment.\n" + "\n" + + " --markdown\n" + + " Generates output in Markdown format.\n" + + "\n" + " -x , --xml-file \n" + " Provides the path to the xml output file.\n" + "\n" + diff --git a/japicmp/src/main/java/japicmp/cli/JApiCli.java b/japicmp/src/main/java/japicmp/cli/JApiCli.java index 9ebf17816..9cd4a8487 100644 --- a/japicmp/src/main/java/japicmp/cli/JApiCli.java +++ b/japicmp/src/main/java/japicmp/cli/JApiCli.java @@ -9,6 +9,7 @@ import japicmp.output.html.HtmlOutputGenerator; import japicmp.output.html.HtmlOutputGeneratorOptions; import japicmp.output.incompatible.IncompatibleErrorOutput; +import japicmp.output.markdown.MarkdownOutputGenerator; import japicmp.output.semver.SemverOut; import japicmp.output.stdout.StdoutOutputGenerator; import japicmp.output.xml.XmlOutput; @@ -69,6 +70,12 @@ private void generateOutput(Options options, List jApiClasses, JarArc throw new JApiCmpException(JApiCmpException.Reason.IoException, "Could not write HTML file: " + e.getMessage(), e); } } + if (options.isMarkdown()) { + MarkdownOutputGenerator markdownOutputGenerator = new MarkdownOutputGenerator(options, jApiClasses); + String output = markdownOutputGenerator.generate(); + System.out.println(output); + return; + } StdoutOutputGenerator stdoutOutputGenerator = new StdoutOutputGenerator(options, jApiClasses); String output = stdoutOutputGenerator.generate(); System.out.println(output); diff --git a/japicmp/src/main/java/japicmp/config/Options.java b/japicmp/src/main/java/japicmp/config/Options.java index f0e132740..c9a696068 100644 --- a/japicmp/src/main/java/japicmp/config/Options.java +++ b/japicmp/src/main/java/japicmp/config/Options.java @@ -42,6 +42,7 @@ public class Options { private boolean reportOnlyFilename; private boolean reportOnlySummary; private boolean semanticVersioning; + private boolean markdown; private boolean errorOnBinaryIncompatibility; private boolean errorOnSourceIncompatibility; private boolean errorOnExclusionIncompatibility = true; @@ -398,6 +399,14 @@ public boolean isSemanticVersioning() { return semanticVersioning; } + public void setMarkdown(boolean markdown) { + this.markdown = markdown; + } + + public boolean isMarkdown() { + return markdown; + } + public boolean isErrorOnBinaryIncompatibility() { return errorOnBinaryIncompatibility; } diff --git a/japicmp/src/main/java/japicmp/output/markdown/Markdown.java b/japicmp/src/main/java/japicmp/output/markdown/Markdown.java new file mode 100644 index 000000000..eba4769ad --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/Markdown.java @@ -0,0 +1,55 @@ +package japicmp.output.markdown; + +import static java.util.stream.Collectors.joining; + +import java.util.stream.Collector; + +public abstract class Markdown { + + public static final String EOL = "\n"; + public static final String PARAGRAPH = "\n\n"; + public static final String SPACE = " "; + public static final String EMPTY = ""; + public static final String DASH = "-"; + public static final String UNDERSCORE = "_"; + public static final String QUOTE = "\""; + public static final String BACKSLASH = "\\"; + public static final String PARENTHESIS_OPEN = "("; + public static final String PARENTHESIS_CLOSE = ")"; + public static final String ANGLE_OPEN = "<"; + public static final String ANGLE_CLOSE = ">"; + public static final String BRACKET_OPEN = "["; + public static final String BRACKET_CLOSE = "]"; + public static final String BANG = "!"; + public static final String HASH = "#"; + public static final String COLON = ":"; + public static final String EQUAL = "="; + public static final String DOT = "."; + public static final char PIPE = '|'; + public static final String BACKTICK = "`"; + public static final String MARKDOWN_HORIZONTAL_RULE = "___"; + public static final Collector LINES = joining(EOL); + public static final Collector SPACES = joining(SPACE); + public static final Collector CSV = joining(", "); + public static final Collector BR = joining("
"); + + public static String quotes(String text) { + return QUOTE + text + QUOTE; + } + + public static String backticks(String text) { + return BACKTICK + text + BACKTICK; + } + + public static String angles(String text) { + return ANGLE_OPEN + text + ANGLE_CLOSE; + } + + public static String brackets(String text) { + return BRACKET_OPEN + text + BRACKET_CLOSE; + } + + public static String parenthesis(String text) { + return PARENTHESIS_OPEN + text + PARENTHESIS_CLOSE; + } +} diff --git a/japicmp/src/main/java/japicmp/output/markdown/MarkdownBadge.java b/japicmp/src/main/java/japicmp/output/markdown/MarkdownBadge.java new file mode 100644 index 000000000..5df2345d1 --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/MarkdownBadge.java @@ -0,0 +1,53 @@ +package japicmp.output.markdown; + +public class MarkdownBadge extends Markdown { + + static final String BASE_URL = "https://img.shields.io/badge/"; + + final String label; + final String message; + final String color; + final String logo; + + public MarkdownBadge(String label, String message, String color, String logo) { + this.label = label; + this.message = message; + this.color = color; + this.logo = logo; + } + + public MarkdownBadge(String label, String message, String color) { + this(label, message, color, null); + } + + @Override + public String toString() { + final String alt = label != null ? label + SPACE + message : message; + return new MarkdownImage(alt, getHref(), alt).toString(); + } + + public MarkdownRefImage toRefImage(MarkdownReferences references, String alt, String title) { + return references.make(getHref(), alt, title).toImage(alt); + } + + public MarkdownRefImage toRefImage(MarkdownReferences references, String title) { + return toRefImage(references, title, title); + } + + public MarkdownRefImage toRefImage(MarkdownReferences references) { + return toRefImage(references, message); + } + + private String getHref() { + final String pre = label == null ? EMPTY : label + .replace(DASH, UNDERSCORE) + .replace(SPACE, UNDERSCORE) + .replace(HASH, COLON) + DASH; + final String msg = message + .replace(DASH, UNDERSCORE) + .replace(SPACE, UNDERSCORE) + .replace(HASH, COLON); + final String arg = logo == null ? EMPTY : "?logo" + EQUAL + logo; + return BASE_URL + pre + msg + DASH + color + arg; + } +} diff --git a/japicmp/src/main/java/japicmp/output/markdown/MarkdownImage.java b/japicmp/src/main/java/japicmp/output/markdown/MarkdownImage.java new file mode 100644 index 000000000..cae245db4 --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/MarkdownImage.java @@ -0,0 +1,13 @@ +package japicmp.output.markdown; + +final class MarkdownImage extends MarkdownLink { + + MarkdownImage(String alt, String href, String title) { + super(alt, href, title); + } + + @Override + public String toString() { + return BANG + super.toString(); + } +} diff --git a/japicmp/src/main/java/japicmp/output/markdown/MarkdownLink.java b/japicmp/src/main/java/japicmp/output/markdown/MarkdownLink.java new file mode 100644 index 000000000..eedb0a194 --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/MarkdownLink.java @@ -0,0 +1,16 @@ +package japicmp.output.markdown; + +class MarkdownLink extends MarkdownReference { + + final String text; + + MarkdownLink(String text, String href, String title) { + super(href, title); + this.text = text == null ? EMPTY : text; + } + + @Override + public String toString() { + return brackets(text) + parenthesis(super.toString()); + } +} diff --git a/japicmp/src/main/java/japicmp/output/markdown/MarkdownList.java b/japicmp/src/main/java/japicmp/output/markdown/MarkdownList.java new file mode 100644 index 000000000..369033d88 --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/MarkdownList.java @@ -0,0 +1,33 @@ +package japicmp.output.markdown; + +import static java.util.Arrays.*; +import static java.util.stream.Collectors.toList; + +import java.util.List; +import java.util.stream.Stream; + +class MarkdownList extends Markdown { + + private final String pad; + private final List elements; + + MarkdownList(String... elements) { + this.pad = EMPTY; + this.elements = asList(elements); + } + + MarkdownList(int level, Stream elements) { + final String format = "%-" + (level * 2) + "s"; + this.pad = String.format(format, EMPTY); + this.elements = elements.collect(toList()); + } + + MarkdownList(int level, String... elements) { + this(level, stream(elements)); + } + + @Override + public String toString() { + return (pad.isEmpty() || elements.isEmpty() ? EMPTY : EOL) + elements.stream().filter(x -> x != null && !x.isEmpty()).map(e -> pad + "- " + e).collect(LINES); + } +} diff --git a/japicmp/src/main/java/japicmp/output/markdown/MarkdownOutputGenerator.java b/japicmp/src/main/java/japicmp/output/markdown/MarkdownOutputGenerator.java new file mode 100644 index 000000000..0666647ef --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/MarkdownOutputGenerator.java @@ -0,0 +1,602 @@ +package japicmp.output.markdown; + +import static japicmp.model.JApiChangeStatus.*; +import static japicmp.output.markdown.Markdown.*; +import static japicmp.util.JApiClassFileFormatVersionHelper.*; +import static japicmp.util.MemberValueHelper.formatMemberValue; +import static japicmp.util.ModifierHelper.*; +import static japicmp.util.OptionalHelper.N_A; +import static japicmp.util.TypeNameHelper.*; +import static java.lang.String.format; +import static java.util.Collections.*; +import static java.util.stream.Collectors.*; + +import japicmp.cmp.JApiCmpArchive; +import japicmp.config.*; +import japicmp.filter.Filter; +import japicmp.model.*; +import japicmp.model.JApiJavaObjectSerializationCompatibility.JApiJavaObjectSerializationChangeStatus; +import japicmp.output.*; +import japicmp.output.markdown.config.MarkdownOptions; +import japicmp.output.semver.SemverOut; +import japicmp.util.Optional; +import java.util.*; +import java.util.regex.Pattern; +import java.util.stream.Stream; +import javassist.bytecode.annotation.MemberValue; + +public class MarkdownOutputGenerator extends OutputGenerator { + + final MarkdownOptions md; + final MarkdownReferences references = new MarkdownReferences(); + + public MarkdownOutputGenerator(MarkdownOptions mdOptions, List jApiClasses) { + super(mdOptions.options, jApiClasses); + md = mdOptions; + } + + public MarkdownOutputGenerator(Options options, List jApiClasses) { + this(MarkdownOptions.newDefault(options), jApiClasses); + } + + @Override + public String generate() { + final String semver = new SemverOut(options, jApiClasses).generate(); + return renderHeading(0, md.title.report) + + md.message.getSemverBadge(semver) + EOL + + renderHeading(1, md.title.summary) + + renderReportSummary(md.message.getSummaryMessage(semver), options) + PARAGRAPH + + renderHtmlDetails(md.message.expandOptions, renderReportOptions(options)) + + renderReportResults(options) + EOL + + renderMissingClassesWarning(options.getIgnoreMissingClasses()) + + MARKDOWN_HORIZONTAL_RULE + PARAGRAPH + + format(md.message.generatedOn, md.message.getCurrentTimestamp()) + PARAGRAPH + + references + EOL; + } + + private String renderHeading(int level, String text) { + final StringBuilder tmp = new StringBuilder(); + tmp.append(EOL); + for (int repeat = 0; repeat < md.title.topHeadingLevel + level && repeat < 6; repeat++) { + tmp.append(HASH); + } + tmp.append(" "); + tmp.append(text); + tmp.append(PARAGRAPH); + return tmp.toString(); + } + + private String renderReportSummary(String summary, Options options) { + final String newVersion = renderArchivesVersion(md.targetNewVersion, options.getNewArchives(), md.message.oneNewVersion, md.message.manyNewArchives); + final String oldVersion = renderArchivesVersion(md.targetOldVersion, options.getOldArchives(), md.message.oneOldVersion, md.message.manyOldArchives); + return format(summary, newVersion, oldVersion); + } + + private String renderReportOptions(Options options) { + final List patterns = options.getIgnoreMissingClasses().getIgnoreMissingClassRegularExpression(); + return new MarkdownList( + format(md.message.reportOnlySummary, md.message.yesNo(options.isReportOnlySummary())), + format(md.message.reportOnlyChanges, md.message.yesNo(options.isOutputOnlyModifications())), + format(md.message.reportOnlyBinaryIncompatibleChanges, md.message.yesNo(options.isOutputOnlyBinaryIncompatibleModifications())), + format(md.message.accessModifierFilter, options.getAccessModifier()), + format(md.message.oldArchives, new MarkdownList(1, options.getOldArchives().stream().map(this::renderArchive))), + format(md.message.newArchives, new MarkdownList(1, options.getNewArchives().stream().map(this::renderArchive))), + format(md.message.evaluateAnnotations, md.message.yesNo(!options.isNoAnnotations())), + format(md.message.includeSynthetic, md.message.yesNo(options.isIncludeSynthetic())), + format(md.message.includeSpecificElements, md.message.yesNo(!options.getIncludes().isEmpty()) + new MarkdownList(1, options.getIncludes().stream().filter(Objects::nonNull).map(Filter::toString).distinct().map(this::renderCode))), + format(md.message.excludeSpecificElements, md.message.yesNo(!options.getExcludes().isEmpty()) + new MarkdownList(1, options.getExcludes().stream().filter(Objects::nonNull).map(Filter::toString).distinct().map(this::renderCode))), + format(md.message.ignoreAllMissingClasses, md.message.yesNo(options.getIgnoreMissingClasses().isIgnoreAllMissingClasses())), + format(md.message.ignoreSpecificMissingClasses, md.message.yesNo(!patterns.isEmpty()) + new MarkdownList(1, patterns.stream().map(Pattern::pattern).map(this::renderCode))), + format(md.message.treatChangesAsErrors, new MarkdownList(1, + format(md.message.anyChanges, md.message.yesNo(options.isErrorOnModifications())), + format(md.message.binaryIncompatibleChanges, md.message.yesNo(options.isErrorOnBinaryIncompatibility())), + format(md.message.sourceIncompatibleChanges, md.message.yesNo(options.isErrorOnSourceIncompatibility())), + format(md.message.incompatibleChangesCausedByExcludedClasses, md.message.yesNo(options.isErrorOnExclusionIncompatibility())), + format(md.message.semanticallyIncompatibleChanges, md.message.yesNo(options.isErrorOnSemanticIncompatibility())), + format(md.message.semanticallyIncompatibleChangesIncludingDevelopmentVersions, md.message.yesNo(options.isErrorOnSemanticIncompatibilityForMajorVersionZero()))) + ), + format(md.message.classpathMode, options.getClassPathMode()), + format(md.message.oldClasspath, options.getOldClassPath().or(EMPTY)), + format(md.message.newClasspath, options.getNewClassPath().or(EMPTY)) + ) + EOL; + } + + private String renderArchivesVersion(Optional version, List archives, String one, String many) { + if (version.isPresent()) { + return format(one, version.get()); + } + if (archives.isEmpty()) { + return format(one, md.message.unknownVersion); + } + if (archives.size() == 1) { + final JApiCmpArchive archive = archives.get(0); + final String archiveVersion = archive.getVersion().getStringVersion(); + if (archiveVersion != null && !archiveVersion.equals(N_A)) { + return format(one, archiveVersion); + } + return format(one, renderSimpleArchiveName(archive)); + } + return many; + } + + private String renderReportResults(Options options) { + new OutputFilter(options).filter(jApiClasses); + if (jApiClasses.isEmpty()) { + return EMPTY; + } + return new MarkdownSection<>(renderHeading(1, md.title.results), jApiClasses, md.sort.classes) + .column(md.header.status, this::renderStatus) + .column(md.header.type, this::renderClassLink) + .column(md.header.serialization, this::renderSerializationChange) + .column(md.header.compatibilityChanges, this::renderAllCompatibilityChanges) + + (md.options.isReportOnlySummary() ? "" : renderHtmlDetails(md.message.expandResults, jApiClasses.stream().sorted(md.sort.classes).map(this::renderClass).collect(joining()))); + } + + private String renderMissingClassesWarning(IgnoreMissingClasses missing) { + if (missing.isIgnoreAllMissingClasses()) { + return md.message.warningAllMissingClassesIgnored; + } else if (!missing.getIgnoreMissingClassRegularExpression().isEmpty()) { + return md.message.warningSomeMissingClassesIgnored; + } + return EMPTY; + } + + private String renderClass(JApiClass clazz) { + final String name = clazz.getFullyQualifiedName(); + return MARKDOWN_HORIZONTAL_RULE + PARAGRAPH + + renderHtmlAnchor(name) + + renderHeading(2, renderCode(name)) + + renderCompatibilityList(clazz) + PARAGRAPH + + renderClassInfo(clazz) + + renderGenericTemplates(clazz) + + renderImplementedInterfaces(clazz) + + renderAnnotations(clazz) + + renderConstructors(clazz) + + renderMethods(clazz) + + renderFields(clazz); + } + + private String renderHtmlAnchor(String id) { + return angles("a" + SPACE + "id" + EQUAL + quotes(renderSlug(id))) + angles("/a"); + } + + private String renderHtmlDetails(String summary, String details) { + return angles("details" + SPACE + "markdown" + EQUAL + quotes("1")) + EOL + + angles("summary") + summary + angles("/summary") + PARAGRAPH + + details + EOL + + angles("/details") + PARAGRAPH; + } + + private String renderSlug(String id) { + return "user-content-" + id.toLowerCase(); + } + + private Markdown renderCompatibilityList(JApiClass clazz) { + return new MarkdownList( + format(md.message.compatibilityBinary, md.message.checkbox(clazz.isBinaryCompatible())), + format(md.message.compatibilitySource, md.message.checkbox(clazz.isSourceCompatible())), + format(md.message.compatibilitySerialization, md.message.checkbox( + !clazz.getJavaObjectSerializationCompatible().isIncompatible()))); + } + + private Markdown renderClassInfo(JApiClass clazz) { + return new MarkdownSection<>(EMPTY, clazz) + .column(md.header.status, this::renderStatus) + .column(md.header.modifiers, this::renderModifiers) + .column(md.header.classType, this::renderClassType) + .column(md.header.className, this::renderClassSimpleName) + .column(md.header.superclass, this::renderClassSuperclass) + .column(md.header.classJdk, this::renderClassJdk) + .column(md.header.serialization, this::renderSerializationChange) + .column(md.header.compatibilityChanges, this::renderClassLevelCompatibilityChanges); + } + + private Markdown renderGenericTemplates(JApiClass clazz) { + return new MarkdownSection<>(renderHeading(3, md.title.generics), clazz.getGenericTemplates(), md.sort.generics) + .column(md.header.status, this::renderStatus) + .column(md.header.genericTemplateName, this::renderGenericTemplateName) + .column(md.header.genericTemplateType, this::renderGenericTemplateType) + .column(md.header.compatibilityChanges, this::renderCompatibilityChanges); + } + + private Markdown renderImplementedInterfaces(JApiClass clazz) { + return new MarkdownSection<>(renderHeading(3, md.title.interfaces), clazz.getInterfaces(), md.sort.interfaces) + .column(md.header.status, this::renderStatus) + .column(md.header.interfaceName, this::renderImplementedInterfaceName) + .column(md.header.compatibilityChanges, this::renderCompatibilityChanges); + } + + private Markdown renderAnnotations(JApiClass clazz) { + return new MarkdownSection<>(renderHeading(3, md.title.annotations), clazz.getAnnotations(), md.sort.annotations) + .column(md.header.status, this::renderStatus) + .column(md.header.annotationName, this::renderAnnotation) + .column(md.header.compatibilityChanges, this::renderAllCompatibilityChanges); + } + + private Markdown renderConstructors(JApiClass clazz) { + return new MarkdownSection<>(renderHeading(3, md.title.constructors), clazz.getConstructors(), md.sort.constructors) + .column(md.header.status, this::renderStatus) + .column(md.header.modifiers, this::renderModifiers) + .column(md.header.generics, this::renderGenericTemplates) + .column(md.header.constructorNameAndParameters, this::renderNameAndParameters) + .column(md.header.annotations, this::renderInlineAnnotations) + .column(md.header.exceptions, this::renderExceptions) + .column(md.header.compatibilityChanges, this::renderAllCompatibilityChanges); + } + + private Markdown renderMethods(JApiClass clazz) { + return new MarkdownSection<>(renderHeading(3, md.title.methods), clazz.getMethods(), md.sort.methods) + .column(md.header.status, this::renderStatus) + .column(md.header.modifiers, this::renderModifiers) + .column(md.header.generics, this::renderGenericTemplates) + .column(md.header.methodReturnType, this::renderReturnType) + .column(md.header.methodNameAndParameters, this::renderNameAndParameters) + .column(md.header.annotations, this::renderInlineAnnotations) + .column(md.header.exceptions, this::renderExceptions) + .column(md.header.compatibilityChanges, this::renderAllCompatibilityChanges); + } + + private Markdown renderFields(JApiClass clazz) { + return new MarkdownSection<>(renderHeading(3, md.title.fields), clazz.getFields(), md.sort.fields) + .column(md.header.status, this::renderStatus) + .column(md.header.modifiers, this::renderModifiers) + .column(md.header.fieldType, this::renderFieldType) + .column(md.header.fieldName, this::renderFieldName) + .column(md.header.annotations, this::renderInlineAnnotations) + .column(md.header.compatibilityChanges, this::renderCompatibilityChanges); + } + + private String renderStatus(JApiHasChangeStatus element) { + final boolean isBinaryCompatible = ((JApiCompatibility) element).isBinaryCompatible(); + final boolean isSourceCompatible = ((JApiCompatibility) element).isSourceCompatible(); + final boolean isSerializationCompatible = !(element instanceof JApiJavaObjectSerializationCompatibility) + || !((JApiJavaObjectSerializationCompatibility) element).getJavaObjectSerializationCompatible().isIncompatible(); + final boolean isFullyCompatible = isBinaryCompatible && isSourceCompatible && isSerializationCompatible; + if (element.getChangeStatus() != UNCHANGED || isFullyCompatible) { + return renderLiteralStatus(element); + } else if (!isBinaryCompatible && !isSourceCompatible) { + return md.message.statusIncompatible; + } else if (!isBinaryCompatible) { + return md.message.statusBinaryIncompatible; + } else if (!isSourceCompatible) { + return md.message.statusSourceIncompatible; + } + return md.message.statusSerializationIncompatible; + } + + private String renderLiteralStatus(JApiHasChangeStatus element) { + switch (element.getChangeStatus()) { + case NEW: + return md.message.statusNew; + case REMOVED: + return md.message.statusRemoved; + case UNCHANGED: + return md.message.statusUnchanged; + default: + case MODIFIED: + return md.message.statusModified; + } + } + + private String renderClassLink(JApiClass clazz) { + final String name = clazz.getFullyQualifiedName(); + return md.options.isReportOnlySummary() ? name : references.link(HASH + renderSlug(name), name, null).toString(); + } + + private String renderClassSimpleName(JApiClass clazz) { + final String simpleName = formatTypeName(clazz.getFullyQualifiedName(), emptyList(), true); + return renderChange(clazz, renderCode(simpleName)); + } + + private String renderClassType(JApiClass clazz) { + final JApiClassType classType = clazz.getClassType(); + return renderChange(classType, md.message.getClassType(classType.getOldTypeOptional()), md.message.getClassType(classType.getNewTypeOptional())); + } + + private String renderClassSuperclass(JApiClass clazz) { + final JApiSuperclass superclass = clazz.getSuperclass(); + final JApiClass correspondingClass = superclass.getCorrespondingJApiClass().or((JApiClass) null); + return renderChange(superclass, + renderTypeWithGenericTemplates(superclass.getOldSuperclassName().or((String) null), superclass, correspondingClass), + renderTypeWithGenericTemplates(superclass.getNewSuperclassName().or((String) null), superclass, correspondingClass)); + } + + private String renderClassJdk(JApiClass clazz) { + final JApiClassFileFormatVersion version = clazz.getClassFileFormatVersion(); + return renderChange(version, getOldJdkVersion(version), getNewJdkVersion(version)); + } + + private String renderGenericTemplateName(JApiGenericTemplate genericTemplate) { + return renderChange(genericTemplate, renderCode(genericTemplate.getName())); + } + + private String renderGenericTemplateType(JApiGenericTemplate genericTemplate) { + return renderChange(genericTemplate, + renderTypeWithGenericTypes(genericTemplate.getOldType(), genericTemplate.getOldGenericTypes()), + renderTypeWithGenericTypes(genericTemplate.getNewType(), genericTemplate.getNewGenericTypes())); + } + + private String renderImplementedInterfaceName(JApiImplementedInterface implInterface) { + return renderChange(implInterface, renderTypeWithGenericTemplates( + implInterface.getFullyQualifiedName(), implInterface, implInterface.getCorrespondingJApiClass().or((JApiClass) null))); + } + + private String renderNameAndParameters(JApiBehavior behavior) { + final String name = behavior.getName(); + final int pos = name != null ? name.lastIndexOf('$') : -1; + final String simpleName = pos > 0 ? name.substring(pos + 1) : name; + return renderChange(behavior, renderCode(simpleName)) + renderParameters(behavior); + } + + private String renderParameters(JApiBehavior behavior) { + return parenthesis(behavior.getParameters().stream().map(x -> renderParameter(behavior, x)).collect(CSV)); + } + + private String renderParameter(JApiBehavior method, JApiParameter parameter) { + if (parameter.getTemplateNameOptional().isPresent()) { + return renderChange(parameter, renderCode(parameter.getTemplateName())); + } + final JApiChangeStatus status = method.getChangeStatus(); + final JApiModifier varargs = method.getVarargsModifier(); + final String oldType = (status == NEW) ? null : renderParameterType(method, parameter, varargs.getOldModifier(), parameter.getOldGenericTypes()); + final String newType = (status == REMOVED) ? null : renderParameterType(method, parameter, varargs.getNewModifier(), parameter.getNewGenericTypes()); + return renderChange(parameter, oldType, newType); + } + + private String renderGenericTemplates(JApiBehavior behavior) { + final List genericTemplates = behavior.getGenericTemplates(); + if (genericTemplates.isEmpty()) { + return EMPTY; + } + return BACKSLASH + ANGLE_OPEN + + genericTemplates.stream().map(this::renderGenericTemplate).collect(CSV) + + BACKSLASH + ANGLE_CLOSE; + } + + private String renderGenericTemplate(JApiGenericTemplate genericTemplate) { + final String name = genericTemplate.getName(); + final String oldTemplate = renderGenericTemplate(name, genericTemplate.getOldTypeOptional().or((String) null), genericTemplate.getOldGenericTypes()); + final String newTemplate = renderGenericTemplate(name, genericTemplate.getNewTypeOptional().or((String) null), genericTemplate.getNewGenericTypes()); + return renderChange(genericTemplate, oldTemplate, newTemplate); + } + + private String renderGenericTemplate(String name, String type, List genericTypes) { + final String fullType = formatGenericTemplate(name, type, genericTypes, false); + final String simpleType = formatGenericTemplate(name, type, genericTypes, true); + return renderCodeWithTooltip(fullType, simpleType); + } + + private String renderCompatibilityChanges(List changes) { + if (changes.isEmpty()) { + return renderNoChangesBadge(); + } + return changes.stream().map(this::renderChangeBadge).collect(SPACES); + } + + private String renderCompatibilityChanges(JApiCompatibility hasCompatibilityChanges) { + return renderCompatibilityChanges(hasCompatibilityChanges.getCompatibilityChanges()); + } + + @SafeVarargs + private final String renderCompatibilityChanges(List... haveCompatibilityChanges) { + return renderCompatibilityChanges(Stream.of(haveCompatibilityChanges).flatMap(List::stream) + .map(JApiCompatibility::getCompatibilityChanges).flatMap(List::stream).distinct().collect(toList())); + } + + private String renderAllCompatibilityChanges(JApiClass clazz) { + final Stream> allCompatibilityChanges = Stream.of( + singletonList(clazz), + singletonList(clazz.getClassFileFormatVersion()), + singletonList(clazz.getSuperclass()), + clazz.getGenericTemplates(), + clazz.getInterfaces(), + clazz.getAnnotations(), + clazz.getAnnotations().stream().map(JApiAnnotation::getElements).flatMap(List::stream).collect(toList()), + clazz.getConstructors(), + clazz.getConstructors().stream().map(JApiConstructor::getParameters).flatMap(List::stream).collect(toList()), + clazz.getMethods(), + clazz.getMethods().stream().map(JApiMethod::getReturnType).collect(toList()), + clazz.getMethods().stream().map(JApiMethod::getParameters).flatMap(List::stream).collect(toList()), + clazz.getFields()); + return renderCompatibilityChanges(allCompatibilityChanges + .flatMap(List::stream) + .map(JApiCompatibility::getCompatibilityChanges) + .flatMap(List::stream) + .distinct().sorted(Comparator.comparing(JApiCompatibilityChange::getType)) + .collect(toList())); + } + + private String renderClassLevelCompatibilityChanges(JApiClass clazz) { + return renderCompatibilityChanges(Arrays.asList(clazz, clazz.getClassFileFormatVersion(), clazz.getSuperclass())); + } + + private String renderAllCompatibilityChanges(JApiAnnotation annotation) { + return renderCompatibilityChanges(singletonList(annotation), annotation.getElements()); + } + + private String renderAllCompatibilityChanges(JApiConstructor constructor) { + return renderCompatibilityChanges(singletonList(constructor), constructor.getParameters()); + } + + private String renderAllCompatibilityChanges(JApiMethod method) { + return renderCompatibilityChanges(singletonList(method), singletonList(method.getReturnType()), method.getParameters()); + } + + private String renderNoChangesBadge() { + return new MarkdownBadge(null, md.message.noCompatibilityChanges, md.message.colorNoChanges) + .toRefImage(references).toString(); + } + + private String renderChangeBadge(JApiCompatibilityChange change) { + final JApiCompatibilityChangeType type = change.getType(); + return new MarkdownBadge(null, md.message.compatibilityChangeType.getOrDefault(type, type.name()), md.message.getSemanticColor(change.getSemanticVersionLevel())) + .toRefImage(references).toString(); + } + + private String renderSerializationChange(JApiClass clazz) { + final JApiJavaObjectSerializationChangeStatus change = clazz.getJavaObjectSerializationCompatible(); + final String text = md.message.serializationCompatibility.getOrDefault(change, change.getDescription()); + final String color = change.isIncompatible() ? md.message.colorMajorChanges : md.message.colorNoChanges; + final String msg = change.isIncompatible() ? md.message.statusIncompatible : text; + return new MarkdownBadge(null, msg, color).toRefImage(references, text).toString(); + } + + private String renderChange(JApiHasChangeStatus hasStatus, String oldValue, String newValue) { + if (oldValue == null && newValue == null) { + return null; + } + switch (hasStatus.getChangeStatus()) { + case NEW: + return newValue == null ? null : format(md.message.added, newValue); + case REMOVED: + return oldValue == null ? null : format(md.message.removed, oldValue); + case UNCHANGED: + if (newValue == null) { + return format(md.message.unchanged, oldValue); + } else if (oldValue == null || newValue.equals(oldValue)) { + return format(md.message.unchanged, newValue); + } + return format(md.message.modified, oldValue, newValue); + default: + case MODIFIED: + if (oldValue == null) { + return format(md.message.added, newValue); + } else if (newValue == null) { + return format(md.message.removed, oldValue); + } else if (newValue.equals(oldValue)) { + return format(md.message.unchanged, newValue); + } + return format(md.message.modified, oldValue, newValue); + } + } + + private String renderChange(JApiHasChangeStatus status, String value) { + return renderChange(status, value, value); + } + + private String renderModifiers(JApiHasModifiers clazz) { + return clazz.getModifiers().stream().map(this::renderModifier) + .filter(Objects::nonNull).collect(SPACES); + } + + private String renderModifier(JApiModifier>> modifier) { + final String oldName = getOldModifierName(modifier).or((String) null); + final String newName = getNewModifierName(modifier).or((String) null); + return renderChange(modifier, renderCode(oldName), renderCode(newName)); + } + + private String renderTypeWithGenericTypes(String type, List genericTypes) { + if (type == null) { + return null; + } + final String fullType = formatTypeName(type, genericTypes, false); + final String simpleType = formatTypeName(type, genericTypes, true); + return renderCodeWithTooltip(fullType, simpleType); + } + + private String renderTypeWithGenericTemplates(String type, JApiHasChangeStatus hasChangeStatus, JApiHasGenericTemplates hasGenericTemplates) { + if (type == null) { + return null; + } + final String fullType = formatTypeName(type, hasChangeStatus, hasGenericTemplates, false); + final String simpleType = formatTypeName(type, hasChangeStatus, hasGenericTemplates, true); + return renderCodeWithTooltip(fullType, simpleType); + } + + private String renderParameterType(JApiBehavior method, JApiParameter parameter, Optional varargs, List genericTypes) { + if (parameter.getType() == null) { + return null; + } + final String fullType = formatParameterTypeName(method, parameter, varargs, genericTypes, false); + final String simpleType = formatParameterTypeName(method, parameter, varargs, genericTypes, true); + return renderCodeWithTooltip(fullType, simpleType); + } + + private String renderMemberValue(Optional optionalValue) { + if (!optionalValue.isPresent()) { + return EMPTY; + } + final String fullValue = formatMemberValue(optionalValue.get(), false); + final String simpleValue = formatMemberValue(optionalValue.get(), true); + return renderCodeWithTooltip(fullValue, simpleValue); + } + + private String renderReturnType(JApiMethod method) { + final JApiReturnType returnType = method.getReturnType(); + return renderChange(returnType, + renderTypeWithGenericTypes(returnType.getOldReturnType(), returnType.getOldGenericTypes()), + renderTypeWithGenericTypes(returnType.getNewReturnType(), returnType.getNewGenericTypes())); + } + + private String renderFieldType(JApiField field) { + final JApiType fieldType = field.getType(); + return renderChange(fieldType, + renderTypeWithGenericTypes(fieldType.getOldValue(), field.getOldGenericTypes()), + renderTypeWithGenericTypes(fieldType.getNewValue(), field.getNewGenericTypes())); + } + + private String renderFieldName(JApiField field) { + return renderCode(field.getName()); + } + + private String renderExceptions(JApiBehavior behavior) { + return behavior.getExceptions().stream().map(this::renderException).collect(CSV); + } + + private String renderException(JApiException exception) { + return renderChange(exception, renderTypeWithGenericTypes(exception.getName(), emptyList())); + } + + private String renderInlineAnnotations(JApiHasAnnotations hasAnnotations) { + return hasAnnotations.getAnnotations().stream().map(this::renderAnnotation).collect(BR); + } + + private String renderAnnotation(JApiAnnotation annotation) { + final String typeName = renderTypeWithGenericTemplates(annotation.getFullyQualifiedName(), annotation, annotation.getCorrespondingJApiClass().or((JApiClass) null)); + return renderChange(annotation, typeName) + + (annotation.getElements().isEmpty() ? EMPTY : COLON + SPACE) + + annotation.getElements().stream().map(this::renderAnnotationElement).collect(CSV); + } + + private String renderAnnotationElement(JApiAnnotationElement element) { + return renderChange(element, renderCode(element.getName())) + EQUAL + + renderChange(element, renderMemberValue(element.getOldValue()), renderMemberValue(element.getNewValue())); + } + + private String renderCode(String text) { + return text == null || text.isEmpty() ? text : backticks(text); + } + + private String renderCodeWithTooltip(String fullType, String simpleType) { + if (fullType.equals(simpleType)) { + return renderCode(simpleType); + } + return references.link(null, renderCode(simpleType), fullType).toString(); + } + + String renderArchive(JApiCmpArchive archive) { + final String label = renderSimpleArchiveName(archive); + final String version = archive.getVersion().getStringVersion(); + final String message = version != null && !version.equals(N_A) ? version : md.message.unknownVersion; + return new MarkdownBadge(label, message, md.message.colorVersionNumber).toString(); + } + + String renderSimpleArchiveName(JApiCmpArchive archive) { + final String version = archive.getVersion().getStringVersion(); + String name = archive.getFile().getName(); + // Drop version from archive name + if (version != null && name.contains(version)) { + name = name.replace(version, EMPTY); + } + // Drop extension from archive name + final int dot = name.lastIndexOf(DOT); + if (dot > 0) { + name = name.substring(0, dot); + } + // Drop trailing dashes or underscores + if (name.endsWith(DASH) || name.endsWith(UNDERSCORE)) { + name = name.substring(0, name.length() - 1); + } + return name; + } +} diff --git a/japicmp/src/main/java/japicmp/output/markdown/MarkdownRefImage.java b/japicmp/src/main/java/japicmp/output/markdown/MarkdownRefImage.java new file mode 100644 index 000000000..aa7a5297a --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/MarkdownRefImage.java @@ -0,0 +1,13 @@ +package japicmp.output.markdown; + +final class MarkdownRefImage extends MarkdownRefLink { + + MarkdownRefImage(String alt, MarkdownStoredReference reference) { + super(alt, reference); + } + + @Override + public String toString() { + return BANG + super.toString(); + } +} diff --git a/japicmp/src/main/java/japicmp/output/markdown/MarkdownRefLink.java b/japicmp/src/main/java/japicmp/output/markdown/MarkdownRefLink.java new file mode 100644 index 000000000..50119f923 --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/MarkdownRefLink.java @@ -0,0 +1,17 @@ +package japicmp.output.markdown; + +class MarkdownRefLink extends Markdown { + private final String text; + private final MarkdownStoredReference reference; + + MarkdownRefLink(String text, MarkdownStoredReference reference) { + this.text = text != null ? text : EMPTY; + this.reference = reference; + } + + @Override + public String toString() { + return brackets(text) + + (text.equals(reference.id) ? EMPTY : brackets(reference.id)); + } +} diff --git a/japicmp/src/main/java/japicmp/output/markdown/MarkdownReference.java b/japicmp/src/main/java/japicmp/output/markdown/MarkdownReference.java new file mode 100644 index 000000000..ce2a09d47 --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/MarkdownReference.java @@ -0,0 +1,40 @@ +package japicmp.output.markdown; + +import japicmp.util.Optional; +import java.util.Objects; + +class MarkdownReference extends Markdown { + + final String href; + final String title; + + MarkdownReference(String href, String title) { + this.href = Optional.fromNullable(href).or(HASH); + this.title = title; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof MarkdownReference) { + final MarkdownReference that = (MarkdownReference) obj; + return Objects.equals(href, that.href) && Objects.equals(title, that.title); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(href, title); + } + + @Override + public String toString() { + if (title == null || title.isEmpty()) { + return href; + } + final String sanitizedTitle = title.replace(QUOTE, BACKSLASH + QUOTE); + return href + SPACE + quotes(sanitizedTitle); + } +} diff --git a/japicmp/src/main/java/japicmp/output/markdown/MarkdownReferences.java b/japicmp/src/main/java/japicmp/output/markdown/MarkdownReferences.java new file mode 100644 index 000000000..8e2c4a2d3 --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/MarkdownReferences.java @@ -0,0 +1,48 @@ +package japicmp.output.markdown; + +import static java.util.Comparator.comparing; + +import java.util.ArrayList; +import java.util.List; + +final class MarkdownReferences extends Markdown { + + private final List references = new ArrayList<>(); + private int referenceId; + + MarkdownStoredReference make(String href, String id, String title) { + final MarkdownReference reference = new MarkdownReference(href, title); + return references.stream().filter(reference::equals).findAny() + .orElseGet(() -> storeReference(id, reference)); + } + + MarkdownRefLink link(String href, String text, String title) { + return make(href, text, title).toLink(text); + } + + private MarkdownStoredReference storeReference(String id, MarkdownReference reference) { + final MarkdownStoredReference stored; + if (isIllegalReferenceId(id) || alreadyUsedReferenceId(id)) { + stored = new MarkdownStoredReference(++referenceId, reference); + } else { + stored = new MarkdownStoredReference(id, reference); + } + references.add(stored); + return stored; + } + + private boolean isIllegalReferenceId(String text) { + return text == null || text.isEmpty() || text.contains(BRACKET_OPEN) || text.contains(BRACKET_CLOSE); + } + + private boolean alreadyUsedReferenceId(String id) { + return references.stream().map(MarkdownStoredReference::getId).anyMatch(id::equals); + } + + @Override + public String toString() { + return references.stream() + .sorted(comparing(MarkdownStoredReference::getIndex).thenComparing(MarkdownStoredReference::getId)) + .map(MarkdownStoredReference::toString).collect(LINES); + } +} diff --git a/japicmp/src/main/java/japicmp/output/markdown/MarkdownSection.java b/japicmp/src/main/java/japicmp/output/markdown/MarkdownSection.java new file mode 100644 index 000000000..4b42b5db0 --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/MarkdownSection.java @@ -0,0 +1,54 @@ +package japicmp.output.markdown; + +import static java.util.Collections.singletonList; +import static java.util.stream.Collectors.toList; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Stream; + +final class MarkdownSection extends Markdown { + + private final String title; + private final List list; + private final Comparator comparator; + private final List> columns = new ArrayList<>(); + + MarkdownSection(String title, List list, Comparator comparator) { + this.title = title; + this.list = list; + this.comparator = comparator; + } + + MarkdownSection(String title, T one) { + this(title, singletonList(one), null); + } + + MarkdownSection column(String header, Function mapper) { + this.columns.add(new Column<>(header, mapper)); + return this; + } + + @Override + public String toString() { + if (list.isEmpty()) { + return EMPTY; + } + final Stream stream = comparator == null ? list.stream() : list.stream().sorted(comparator); + final MarkdownTable table = new MarkdownTable(columns.stream().map(column -> column.header).collect(toList())); + stream.forEach(x -> table.addRow(columns.stream().map(column -> column.mapper.apply(x)).collect(toList()))); + return title + table; + } + + private static final class Column { + final String header; + final Function mapper; + + Column(String header, Function mapper) { + this.header = header; + this.mapper = mapper; + } + } +} diff --git a/japicmp/src/main/java/japicmp/output/markdown/MarkdownStoredReference.java b/japicmp/src/main/java/japicmp/output/markdown/MarkdownStoredReference.java new file mode 100644 index 000000000..da41bb672 --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/MarkdownStoredReference.java @@ -0,0 +1,41 @@ +package japicmp.output.markdown; + +final class MarkdownStoredReference extends MarkdownReference { + final int index; + final String id; + + MarkdownStoredReference(int index, String id, MarkdownReference reference) { + super(reference.href, reference.title); + this.index = index; + this.id = id; + } + + MarkdownStoredReference(String id, MarkdownReference reference) { + this(Integer.MAX_VALUE, id, reference); + } + + MarkdownStoredReference(int index, MarkdownReference reference) { + this(index, String.valueOf(index), reference); + } + + int getIndex() { + return index; + } + + String getId() { + return id; + } + + MarkdownRefImage toImage(String alt) { + return new MarkdownRefImage(alt, this); + } + + MarkdownRefLink toLink(String text) { + return new MarkdownRefLink(text, this); + } + + @Override + public String toString() { + return brackets(id) + COLON + SPACE + super.toString(); + } +} diff --git a/japicmp/src/main/java/japicmp/output/markdown/MarkdownTable.java b/japicmp/src/main/java/japicmp/output/markdown/MarkdownTable.java new file mode 100644 index 000000000..66af1154e --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/MarkdownTable.java @@ -0,0 +1,97 @@ +package japicmp.output.markdown; + +import static java.util.stream.Collectors.joining; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.*; + +final class MarkdownTable extends Markdown { + + final int columns; + final List> rows = new ArrayList<>(); + + MarkdownTable(List headers) { + columns = headers.size(); + rows.add(headers); + } + + static String getColumnFormat(int width) { + return width < 1 ? "%s" : "%-" + width + "s"; + } + + void addRow(List row) { + rows.add(row); + } + + @Override + public String toString() { + if (rows.size() == 1) { + return EMPTY; + } + final Map colWidths = calculateColumnWidths(); + return IntStream.range(0, rows.size()).mapToObj(r -> { + final List row = rows.get(r); + final StringBuilder tmp = new StringBuilder(); + tmp.append(new Row(row, colWidths)); + if (r == 0) { + tmp.append(PIPE); + IntStream.range(0, columns).forEach(index -> tmp + .append(DASH) + .append(String.format(getColumnFormat(colWidths.get(index)), EMPTY).replace(SPACE, DASH)) + .append(DASH) + .append(PIPE)); + tmp.append(EOL); + } + return tmp.toString(); + }).collect(joining()) + EOL; + } + + private Map calculateColumnWidths() { + return IntStream.range(0, columns).mapToObj(Integer.class::cast) + .collect(Collectors.toMap(Function.identity(), this::calculateMaxWidth)); + } + + private int calculateMaxWidth(int index) { + if (index + 1 < columns) { + // Columns adjust dynamically up to a fixed limit + return rows.stream().map(x -> x.get(index)).mapToInt(String::length).filter(x -> x <= 64).max().orElse(0); + } + // Last column adjusts to heading size + return rows.get(0).get(index).length(); + } + + private class Row { + + final List data; + final Map widths; + int offset = 0; + + Row(List data, Map widths) { + this.data = data; + this.widths = widths; + } + + String formatColumn(int index) { + final int width = widths.get(index); + final int maxWidth = Math.max(0, width - offset); + final String formatted = String.format(getColumnFormat(maxWidth), data.get(index)); + final int length = formatted.length(); + if (length <= width) { + offset -= width - length; + } else if (length > maxWidth) { + offset += length - maxWidth; + } + offset = Math.max(0, offset); + return formatted; + } + + @Override + public String toString() { + return PIPE + IntStream.range(0, columns) + .mapToObj(index -> SPACE + formatColumn(index) + SPACE + PIPE) + .collect(joining()) + + EOL; + } + } +} diff --git a/japicmp/src/main/java/japicmp/output/markdown/config/MarkdownHeaderOptions.java b/japicmp/src/main/java/japicmp/output/markdown/config/MarkdownHeaderOptions.java new file mode 100644 index 000000000..487ed83da --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/config/MarkdownHeaderOptions.java @@ -0,0 +1,26 @@ +package japicmp.output.markdown.config; + +public class MarkdownHeaderOptions { + + public String annotationName = "Annotation"; + public String annotations = "Annotations"; + public String className = "Name"; + public String classType = "Type"; + public String compatibilityChanges = "Compatibility Changes"; + public String constructorNameAndParameters = "Constructor"; + public String exceptions = "Throws"; + public String fieldName = "Name"; + public String fieldType = "Type"; + public String genericTemplateName = "Name"; + public String genericTemplateType = "Extends"; + public String generics = "Generics"; + public String interfaceName = "Interface"; + public String classJdk = "JDK"; + public String methodNameAndParameters = "Method"; + public String methodReturnType = "Type"; + public String modifiers = "Modifiers"; + public String serialization = "Serialization"; + public String status = "Status"; + public String superclass = "Extends"; + public String type = "Type"; +} diff --git a/japicmp/src/main/java/japicmp/output/markdown/config/MarkdownMessageOptions.java b/japicmp/src/main/java/japicmp/output/markdown/config/MarkdownMessageOptions.java new file mode 100644 index 000000000..3acb77331 --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/config/MarkdownMessageOptions.java @@ -0,0 +1,187 @@ +package japicmp.output.markdown.config; + +import static japicmp.output.markdown.Markdown.*; +import static japicmp.output.semver.SemverOut.*; +import static java.util.Arrays.stream; +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.toMap; + +import japicmp.model.*; +import japicmp.model.JApiJavaObjectSerializationCompatibility.JApiJavaObjectSerializationChangeStatus; +import japicmp.output.markdown.MarkdownBadge; +import japicmp.util.Optional; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Map; + +public class MarkdownMessageOptions { + + public String summaryMajorChanges = "> [!CAUTION]\n>\n> Incompatible changes found while checking backward compatibility of %s with %s."; + public String summaryMinorChanges = "> [!WARNING]\n>\n> Compatible changes found while checking backward compatibility of %s with %s."; + public String summaryPatchChanges = "> [!IMPORTANT]\n>\n> Compatible bug fixes found while checking backward compatibility of %s with %s."; + public String summaryNoChanges = "> [!NOTE]\n>\n> No incompatible changes found while checking backward compatibility of %s with %s."; + + public String oneNewVersion = "version `%s`"; + public String oneOldVersion = "the previous version `%s`"; + public String manyNewArchives = "several archives"; + public String manyOldArchives = "their previous versions"; + public String unknownVersion = "unknown"; + public String expandResults = "Expand for details."; + public String expandOptions = "Expand to see options used."; + + public String warningAllMissingClassesIgnored = "> [!WARNING]\n>\n> All missing classes, i.e. superclasses and interfaces that could not be found on the classpath were ignored.\n>\n> Hence changes caused by these superclasses and interfaces are not reflected in the output.\n\n"; + public String warningSomeMissingClassesIgnored = "> [!WARNING]\n>\n> Certain classes, i.e. superclasses and interfaces that could not be found on the classpath were ignored.\n>\n> Hence changes caused by these superclasses and interfaces are not reflected in the output.\n\n"; + + public String generatedOn = "*Generated on: %s*."; + public String dateTimeFormat = "yyyy-MM-dd HH:mm:ss.SSSZ"; + + public String classpathMode = "**Classpath mode**: `%s`"; + public String oldArchives = "**Old archives**:%s"; + public String newArchives = "**New archives**:%s"; + public String oldClasspath = "**Old classpath**:\n```\n%s\n```"; + public String newClasspath = "**New classpath**:\n```\n%s\n```"; + public String accessModifierFilter = "**Access modifier filter**: `%s`"; + public String evaluateAnnotations = "**Evaluate annotations**: %s"; + public String reportOnlySummary = "**Report only summary**: %s"; + public String reportOnlyChanges = "**Report only changes**: %s"; + public String reportOnlyBinaryIncompatibleChanges = "**Report only binary-incompatible changes**: %s"; + public String includeSpecificElements = "**Include specific elements**: %s"; + public String includeSynthetic = "**Include synthetic classes and class members**: %s"; + public String excludeSpecificElements = "**Exclude specific elements**: %s"; + public String ignoreAllMissingClasses = "**Ignore all missing classes**: %s"; + public String ignoreSpecificMissingClasses = "**Ignore specific missing classes**: %s"; + public String treatChangesAsErrors = "**Treat changes as errors**:%s"; + + public String anyChanges = "Any changes: %s"; + public String binaryIncompatibleChanges = "Binary incompatible changes: %s"; + public String sourceIncompatibleChanges = "Source incompatible changes: %s"; + public String incompatibleChangesCausedByExcludedClasses = "Incompatible changes caused by excluded classes: %s"; + public String semanticallyIncompatibleChanges = "Semantically incompatible changes: %s"; + public String semanticallyIncompatibleChangesIncludingDevelopmentVersions = "Semantically incompatible changes, including development versions: %s"; + + public String added = "**%s**"; + public String removed = "~~%s~~"; + public String modified = "~~%s~~ → **%s**"; + public String unchanged = "%s"; + + public String yes = "Yes"; + public String no = "No"; + + public String checked = "[X]"; + public String unchecked = "[ ]"; + + public String compatibilityBinary = "%s Binary-compatible"; + public String compatibilitySource = "%s Source-compatible"; + public String compatibilitySerialization = "%s Serialization-compatible"; + + public String noCompatibilityChanges = "No changes"; + + public String colorMajorChanges = "red"; + public String colorMinorChanges = "orange"; + public String colorPatchChanges = "yellow"; + public String colorNoChanges = "green"; + public String colorVersionNumber = "blue"; + + public String badgeMajorChanges = new MarkdownBadge("semver", "MAJOR", colorMajorChanges, "semver").toString(); + public String badgeMinorChanges = new MarkdownBadge("semver", "MINOR", colorMinorChanges, "semver").toString(); + public String badgePatchChanges = new MarkdownBadge("semver", "PATCH", colorPatchChanges, "semver").toString(); + public String badgeNoChanges = new MarkdownBadge("semver", "OK", colorNoChanges, "semver").toString(); + + public String typeAnnotation = "Annotation"; + public String typeInterface = "Interface"; + public String typeClass = "Class"; + public String typeEnum = "Enum"; + + public String statusNew = "Added"; + public String statusRemoved = "Removed"; + public String statusModified = "Modified"; + public String statusUnchanged = "Unchanged"; + public String statusIncompatible = "Incompatible"; + public String statusSourceIncompatible = "Source-incompatible"; + public String statusBinaryIncompatible = "Binary-incompatible"; + public String statusSerializationIncompatible = "Serialization-incompatible"; + + public Map serializationCompatibility = + stream(JApiJavaObjectSerializationChangeStatus.values()).collect(toMap(identity(), e -> capitalize(e.getDescription()))); + + public Map compatibilityChangeType = + stream(JApiCompatibilityChangeType.values()).collect(toMap(identity(), e -> capitalize(e.name()))); + + private static String capitalize(String text) { + return text.substring(0, 1).toUpperCase() + text.substring(1).toLowerCase().replace(UNDERSCORE, SPACE); + } + + public String getSemanticColor(JApiSemanticVersionLevel level) { + switch (level) { + default: + case MAJOR: + return colorMajorChanges; + case MINOR: + return colorMinorChanges; + case PATCH: + return colorPatchChanges; + } + } + + public String getSemverBadge(String semver) { + switch (semver) { + case SEMVER_MAJOR: + return badgeMajorChanges; + case SEMVER_MINOR: + return badgeMinorChanges; + case SEMVER_PATCH: + return badgePatchChanges; + case SEMVER_COMPATIBLE: + default: + return badgeNoChanges; + } + } + + public String getSummaryMessage(String semver) { + switch (semver) { + case SEMVER_MAJOR: + return summaryMajorChanges; + case SEMVER_MINOR: + return summaryMinorChanges; + case SEMVER_PATCH: + return summaryPatchChanges; + case SEMVER_COMPATIBLE: + default: + return summaryNoChanges; + } + } + + public String getClassType(Optional classType) { + if (!classType.isPresent()) { + return EMPTY; + } + switch (classType.get()) { + case ANNOTATION: + return typeAnnotation; + case INTERFACE: + return typeInterface; + default: + case CLASS: + return typeClass; + case ENUM: + return typeEnum; + } + } + + public String getCurrentTimestamp() { + final ZonedDateTime now = ZonedDateTime.now(); + try { + return DateTimeFormatter.ofPattern(dateTimeFormat).format(now); + } catch (Exception e) { + return now.toString(); + } + } + + public String yesNo(boolean value) { + return value ? yes : no; + } + + public String checkbox(boolean value) { + return value ? checked : unchecked; + } +} diff --git a/japicmp/src/main/java/japicmp/output/markdown/config/MarkdownOptions.java b/japicmp/src/main/java/japicmp/output/markdown/config/MarkdownOptions.java new file mode 100644 index 000000000..2898620ee --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/config/MarkdownOptions.java @@ -0,0 +1,37 @@ +package japicmp.output.markdown.config; + +import japicmp.config.Options; +import japicmp.util.Optional; + +public class MarkdownOptions { + + public Options options; + + public Optional targetOldVersion = Optional.absent(); + public Optional targetNewVersion = Optional.absent(); + + public MarkdownTitleOptions title = new MarkdownTitleOptions(); + public MarkdownHeaderOptions header = new MarkdownHeaderOptions(); + public MarkdownSortOptions sort = new MarkdownSortOptions(); + public MarkdownMessageOptions message = new MarkdownMessageOptions(); + + MarkdownOptions(Options options) { + this.options = options != null ? options : Options.newDefault(); + } + + public static MarkdownOptions newDefault() { + return new MarkdownOptions(null); + } + + public static MarkdownOptions newDefault(Options options) { + return new MarkdownOptions(options); + } + + public void setTargetOldVersion(String targetOldVersion) { + this.targetOldVersion = Optional.fromNullable(targetOldVersion); + } + + public void setTargetNewVersion(String targetNewVersion) { + this.targetNewVersion = Optional.fromNullable(targetNewVersion); + } +} diff --git a/japicmp/src/main/java/japicmp/output/markdown/config/MarkdownSortOptions.java b/japicmp/src/main/java/japicmp/output/markdown/config/MarkdownSortOptions.java new file mode 100644 index 000000000..3aeb2567b --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/config/MarkdownSortOptions.java @@ -0,0 +1,23 @@ +package japicmp.output.markdown.config; + +import static java.util.Comparator.comparing; + +import japicmp.model.JApiAnnotation; +import japicmp.model.JApiClass; +import japicmp.model.JApiConstructor; +import japicmp.model.JApiField; +import japicmp.model.JApiGenericTemplate; +import japicmp.model.JApiImplementedInterface; +import japicmp.model.JApiMethod; +import java.util.Comparator; + +public class MarkdownSortOptions { + + public Comparator classes = comparing(JApiClass::getFullyQualifiedName); + public Comparator generics = null; + public Comparator interfaces = comparing(JApiImplementedInterface::getFullyQualifiedName); + public Comparator annotations = comparing(JApiAnnotation::getFullyQualifiedName); + public Comparator constructors = null; + public Comparator methods = comparing(JApiMethod::getName); + public Comparator fields = comparing(JApiField::getName); +} diff --git a/japicmp/src/main/java/japicmp/output/markdown/config/MarkdownTitleOptions.java b/japicmp/src/main/java/japicmp/output/markdown/config/MarkdownTitleOptions.java new file mode 100644 index 000000000..4356093ce --- /dev/null +++ b/japicmp/src/main/java/japicmp/output/markdown/config/MarkdownTitleOptions.java @@ -0,0 +1,15 @@ +package japicmp.output.markdown.config; + +public class MarkdownTitleOptions { + + public int topHeadingLevel = 1; + public String report = "Compatibility Report"; + public String summary = "Summary"; + public String results = "Results"; + public String generics = "Generics"; + public String interfaces = "Implemented Interfaces"; + public String annotations = "Annotations"; + public String constructors = "Constructors"; + public String methods = "Methods"; + public String fields = "Fields"; +} diff --git a/japicmp/src/main/java/japicmp/util/JApiClassFileFormatVersionHelper.java b/japicmp/src/main/java/japicmp/util/JApiClassFileFormatVersionHelper.java new file mode 100644 index 000000000..58569548e --- /dev/null +++ b/japicmp/src/main/java/japicmp/util/JApiClassFileFormatVersionHelper.java @@ -0,0 +1,36 @@ +package japicmp.util; + +import japicmp.model.JApiClassFileFormatVersion; + +public class JApiClassFileFormatVersionHelper { + + private JApiClassFileFormatVersionHelper() { + } + + public static String getOldJdkVersion(JApiClassFileFormatVersion x) { + return getJdkVersion(x.getMajorVersionOld(), x.getMinorVersionOld()); + } + + public static String getNewJdkVersion(JApiClassFileFormatVersion x) { + return getJdkVersion(x.getMajorVersionNew(), x.getMinorVersionNew()); + } + + private static String getJdkVersion(int major, int minor) { + if (major == -1 || minor == -1) { + return ""; + } + if (major == 45) { + return minor < 3 ? "JDK 1.0" : "JDK 1.1"; + } else if (major == 46) { + return "JDK 1.2"; + } else if (major == 47) { + return "JDK 1.3"; + } else if (major == 48) { + return "JDK 1.4"; + } else if (major >= 49 && major <= 70) { + // JDK 5 to 26, according to: https://andbin.github.io/java-versions-cheat-sheet/ + return "JDK " + (major - 44); + } + return "Version " + major + "." + minor; + } +} diff --git a/japicmp/src/main/java/japicmp/util/MemberValueHelper.java b/japicmp/src/main/java/japicmp/util/MemberValueHelper.java new file mode 100644 index 000000000..72814411b --- /dev/null +++ b/japicmp/src/main/java/japicmp/util/MemberValueHelper.java @@ -0,0 +1,59 @@ +package japicmp.util; + +import static japicmp.util.TypeNameHelper.formatTypeName; +import static java.util.Collections.emptyList; +import static java.util.stream.Collectors.joining; +import static java.util.Arrays.stream; + +import java.util.Set; +import javassist.bytecode.annotation.*; + +public class MemberValueHelper { + + private MemberValueHelper() { + } + + /** + * Formats an annotation's member value. + * + * @param value The member value. + * @param shorten Whether to truncate types to 32 characters or not. + * @return The formatted member value. + */ + public static String formatMemberValue(MemberValue value, boolean shorten) { + if (value instanceof AnnotationMemberValue) { + final Annotation annotation = ((AnnotationMemberValue) value).getValue(); + final Set names = annotation.getMemberNames(); + final String typeName = formatTypeName(annotation.getTypeName(), emptyList(), shorten); + if (names.isEmpty()) { + return typeName; + } + return typeName + "(" + names.stream().map(annotation::getMemberValue).map(MemberValue::toString).collect(joining(", ")) + ")"; + } else if (value instanceof ArrayMemberValue) { + return "{" + stream(((ArrayMemberValue) value).getValue()).map(x -> formatMemberValue(x, shorten)).collect(joining(", ")) + "}"; + } else if (value instanceof BooleanMemberValue) { + return Boolean.toString(((BooleanMemberValue) value).getValue()); + } else if (value instanceof ByteMemberValue) { + return Byte.toString(((ByteMemberValue) value).getValue()); + } else if (value instanceof CharMemberValue) { + return Character.toString(((CharMemberValue) value).getValue()); + } else if (value instanceof FloatMemberValue) { + return Float.toString(((FloatMemberValue) value).getValue()); + } else if (value instanceof DoubleMemberValue) { + return Double.toString(((DoubleMemberValue) value).getValue()); + } else if (value instanceof ShortMemberValue) { + return Short.toString(((ShortMemberValue) value).getValue()); + } else if (value instanceof IntegerMemberValue) { + return Integer.toString(((IntegerMemberValue) value).getValue()); + } else if (value instanceof LongMemberValue) { + return Long.toString(((LongMemberValue) value).getValue()); + } else if (value instanceof EnumMemberValue) { + return shorten ? ((EnumMemberValue) value).getValue() : value.toString(); + } else if (value instanceof StringMemberValue) { + return "\"" + ((StringMemberValue) value).getValue() + "\""; + } else if (value instanceof ClassMemberValue) { + return TypeNameHelper.formatTypeName(((ClassMemberValue) value).getValue(), emptyList(), shorten); + } + return value.toString(); + } +} diff --git a/japicmp/src/main/java/japicmp/util/ModifierHelper.java b/japicmp/src/main/java/japicmp/util/ModifierHelper.java index 98a6e2387..5f5ece8dc 100644 --- a/japicmp/src/main/java/japicmp/util/ModifierHelper.java +++ b/japicmp/src/main/java/japicmp/util/ModifierHelper.java @@ -2,15 +2,23 @@ import japicmp.cmp.JarArchiveComparatorOptions; import japicmp.config.Options; +import japicmp.model.AbstractModifier; import japicmp.model.AccessModifier; +import japicmp.model.BridgeModifier; +import japicmp.model.FinalModifier; import japicmp.model.JApiAttribute; import japicmp.model.JApiCanBeSynthetic; import japicmp.model.JApiChangeStatus; import japicmp.model.JApiHasAccessModifier; import japicmp.model.JApiModifier; import japicmp.model.JApiModifierBase; +import japicmp.model.StaticModifier; import japicmp.model.SyntheticAttribute; import japicmp.model.SyntheticModifier; +import japicmp.model.TransientModifier; +import japicmp.model.VolatileModifier; +import java.util.Arrays; +import java.util.List; import javassist.CtBehavior; import javassist.CtClass; import javassist.CtField; @@ -21,6 +29,17 @@ public class ModifierHelper { public static final int ACC_BRIDGE = 0x00000040; public static final int ACC_SYNTHETIC = 0x00001000; + private static final List IGNORED_MODIFIERS = Arrays.asList( + AbstractModifier.NON_ABSTRACT, + AccessModifier.PACKAGE_PROTECTED, + BridgeModifier.NON_BRIDGE, + FinalModifier.NON_FINAL, + StaticModifier.NON_STATIC, + SyntheticModifier.NON_SYNTHETIC, + TransientModifier.NON_TRANSIENT, + VolatileModifier.NON_VOLATILE + ); + private ModifierHelper() { } @@ -217,6 +236,19 @@ public static boolean isSynthetic(JApiCanBeSynthetic jApiClass) { return isSynthetic; } + public static Optional getOldModifierName(JApiModifier>> modifier) { + return getModifierName(modifier.getOldModifier()); + } + + public static Optional getNewModifierName(JApiModifier>> modifier) { + return getModifierName(modifier.getNewModifier()); + } + + private static Optional getModifierName(Optional> modifier) { + return !modifier.isPresent() || IGNORED_MODIFIERS.contains(modifier.get()) ? Optional.absent() : + Optional.of(modifier.get().name().toLowerCase()); + } + private static boolean hasSyntheticAttribute(JApiAttribute syntheticAttribute) { boolean hasSyntheticAttribute = false; if (syntheticAttribute.getOldAttribute().isPresent() && syntheticAttribute.getNewAttribute().isPresent()) { diff --git a/japicmp/src/main/java/japicmp/util/TypeNameHelper.java b/japicmp/src/main/java/japicmp/util/TypeNameHelper.java new file mode 100644 index 000000000..72800e46b --- /dev/null +++ b/japicmp/src/main/java/japicmp/util/TypeNameHelper.java @@ -0,0 +1,183 @@ +package japicmp.util; + +import static japicmp.model.VarargsModifier.*; +import static java.util.stream.Collectors.joining; + +import japicmp.model.*; +import java.util.List; + +public class TypeNameHelper { + + private static final String STR_ARRAY = "[]"; + private static final String STR_VARARGS = "..."; + + private TypeNameHelper() { + } + + /** + * Formats a generic template. + * + * @param name The generic template name. + * @param type The type extended by the generic template. + * @param genericTypes The generic types of the generic template. + * @param shorten Whether to truncate types to 32 characters or not. + * @return A string with the format {@code "NAME extends TYPE"}. + */ + public static String formatGenericTemplate(String name, String type, List genericTypes, boolean shorten) { + return type == null ? name : name + " extends " + formatTypeName(type, genericTypes, shorten); + } + + /** + * Formats a Java type in FQN form plus generic types. + * + * @param typeName The fully qualified type name to format. + * @param genericTypes The possibly empty list of generic types. + * @param maxLength The maximum number of characters that will be produced. + * If greater or equal to 3, the FQN will be truncated to its simple name, + * and surplus characters will be replaced with the ellipsis character. + * @return The formatted type. + */ + public static String formatTypeName(String typeName, List genericTypes, int maxLength) { + if (typeName == null || typeName.isEmpty() || typeName.equals(OptionalHelper.N_A)) { + return typeName; + } + return truncateTypeName(typeName, maxLength) + formatGenericTypes(genericTypes, maxLength); + } + + /** + * Formats a Java type in FQN form plus generic templates. + * + * @param typeName The fully qualified type name to format. + * @param hasChangeStatus The element that has a change status. + * @param hasGenericTemplates The element that has generic templates. + * @param maxLength The maximum number of characters that will be produced. + * If greater or equal to 3, the FQN will be truncated to its simple name, + * and surplus characters will be replaced with the ellipsis character. + * @return The formatted type. + */ + public static String formatTypeName(String typeName, JApiHasChangeStatus hasChangeStatus, JApiHasGenericTemplates hasGenericTemplates, int maxLength) { + if (typeName == null || typeName.isEmpty() || typeName.equals(OptionalHelper.N_A)) { + return typeName; + } + return truncateTypeName(typeName, maxLength) + (hasGenericTemplates == null ? "" + : formatGenericTemplates(hasChangeStatus, hasGenericTemplates.getGenericTemplates(), maxLength)); + } + + /** + * Formats a Java type in FQN form plus generic types. + * + * @param type The fully qualified name to format. + * @param genericTypes The possibly empty list of generic types. + * @param shorten Whether to truncate the type to 32 characters or not. + * @return The formatted type. + */ + public static String formatTypeName(String type, List genericTypes, boolean shorten) { + return formatTypeName(type, genericTypes, shorten ? 32 : -1); + } + + /** + * Formats a Java type in FQN form plus generic templates. + * + * @param typeName The fully qualified type name to format. + * @param hasChangeStatus The element that has a change status. + * @param hasGenericTemplates The element that has generic templates. + * @param shorten Whether to truncate the type to 32 characters or not. + * @return The formatted type. + */ + public static String formatTypeName(String typeName, JApiHasChangeStatus hasChangeStatus, JApiHasGenericTemplates hasGenericTemplates, boolean shorten) { + return formatTypeName(typeName, hasChangeStatus, hasGenericTemplates, shorten ? 32 : -1); + } + + /** + * Formats a parameter type plus generic types. + * + * @param method The method this parameter belongs to. + * @param parameter The parameter whose type will be formatted. + * @param varargs The varargs modifier of the method. + * @param genericTypes The possibly empty list of generic types. + * @param shorten Whether to truncate the type to 32 characters or not. + * @return The formatted type. + */ + public static String formatParameterTypeName(JApiBehavior method, JApiParameter parameter, Optional varargs, List genericTypes, boolean shorten) { + final String type = parameter.getType(); + final List params = method.getParameters(); + if (type.endsWith(STR_ARRAY) && parameter == params.get(params.size() - 1) && varargs.or(NON_VARARGS) == VARARGS) { + return formatTypeName(type.substring(0, type.length() - 2) + STR_VARARGS, genericTypes, shorten); + } + return formatTypeName(type, genericTypes, shorten); + } + + private static String formatGenericTypes(List genericTypes, int maxLength) { + if (genericTypes == null || genericTypes.isEmpty()) { + return ""; + } + return "<" + genericTypes.stream().map(x -> formatGenericType(x, maxLength)).collect(joining(", ")) + ">"; + } + + private static String formatGenericTemplates(JApiHasChangeStatus hasChangeStatus, List genericTemplates, int maxLength) { + if (genericTemplates == null || genericTemplates.isEmpty()) { + return ""; + } + return "<" + genericTemplates.stream().map(x -> formatGenericTemplate(hasChangeStatus, x, maxLength)).collect(joining(", ")) + ">"; + } + + private static String formatGenericType(JApiGenericType genericType, int maxLength) { + switch (genericType.getGenericWildCard()) { + case NONE: + return formatTypeName(genericType.getType(), genericType.getGenericTypes(), maxLength); + default: + case UNBOUNDED: + return "?"; + case EXTENDS: + return "? extends " + formatTypeName(genericType.getType(), genericType.getGenericTypes(), maxLength); + case SUPER: + return "? super " + formatTypeName(genericType.getType(), genericType.getGenericTypes(), maxLength); + } + } + + private static String formatGenericTemplate(JApiHasChangeStatus hasChangeStatus, JApiGenericTemplate genericTemplate, int maxLength) { + final String name = genericTemplate.getName(); + String type = null; + List genericTypes = null; + if (maxLength <= 0) { + switch (hasChangeStatus.getChangeStatus()) { + default: + case MODIFIED: + case NEW: + if (genericTemplate.getNewTypeOptional().isPresent()) { + type = genericTemplate.getNewType(); + genericTypes = genericTemplate.getNewGenericTypes(); + break; + } + case UNCHANGED: + case REMOVED: + if (genericTemplate.getOldTypeOptional().isPresent()) { + type = genericTemplate.getOldType(); + genericTypes = genericTemplate.getOldGenericTypes(); + } + } + } + if (type == null) { + return name; + } + return name + " extends " + formatTypeName(type, genericTypes, maxLength); + } + + private static String truncateTypeName(String typeName, int maxLength) { + if (maxLength < 3) { + return typeName; + } + // Enforcing max length implies sticking to simple name only + final int dollar = typeName.lastIndexOf('$'); + final int dot = (typeName.endsWith(STR_VARARGS) ? typeName.substring(0, typeName.length() - 3) : typeName).lastIndexOf('.'); + final int pos = Integer.max(dollar, dot); + final String name = pos > 0 ? typeName.substring(pos + 1) : typeName; + final int length = name.length(); + if (length > maxLength) { + // Cut in half and replace surplus characters with ellipsis + final int half = maxLength / 2; + return name.substring(0, maxLength - half - 1) + '\u2026' + name.substring(length - half); + } + return name; + } +} diff --git a/japicmp/src/test/java/japicmp/output/markdown/MarkdownOutputGeneratorTest.java b/japicmp/src/test/java/japicmp/output/markdown/MarkdownOutputGeneratorTest.java new file mode 100644 index 000000000..07e2af4e8 --- /dev/null +++ b/japicmp/src/test/java/japicmp/output/markdown/MarkdownOutputGeneratorTest.java @@ -0,0 +1,296 @@ +package japicmp.output.markdown; + +import static japicmp.model.AccessModifier.PRIVATE; +import static japicmp.model.JApiCompatibilityChangeType.FIELD_GENERICS_CHANGED; +import static japicmp.model.JApiCompatibilityChangeType.METHOD_PARAMETER_GENERICS_CHANGED; +import static japicmp.model.JApiCompatibilityChangeType.METHOD_REMOVED; +import static japicmp.model.JApiCompatibilityChangeType.METHOD_RETURN_TYPE_GENERICS_CHANGED; +import static japicmp.model.JApiJavaObjectSerializationCompatibility.JApiJavaObjectSerializationChangeStatus.NOT_SERIALIZABLE; +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; + +import japicmp.cmp.ClassesHelper; +import japicmp.cmp.JApiCmpArchive; +import japicmp.cmp.JarArchiveComparatorOptions; +import japicmp.config.Options; +import japicmp.model.JApiClass; +import japicmp.output.markdown.config.MarkdownMessageOptions; +import japicmp.output.markdown.config.MarkdownOptions; +import japicmp.util.CtClassBuilder; +import japicmp.util.CtFieldBuilder; +import japicmp.util.CtInterfaceBuilder; +import japicmp.util.CtMethodBuilder; +import java.io.File; +import java.util.Arrays; +import java.util.List; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtField; +import javassist.CtMethod; +import org.junit.Assert; +import org.junit.Test; + +public class MarkdownOutputGeneratorTest { + + static final String TEST_CLASS_FQN = "japicmp.Test"; + static final String TEST_INTERFACE_NAME = "MyInterface"; + static final String TEST_METHOD_NAME = "method"; + static final String TEST_METHOD_BODY = "return;"; + static final String TEST_FIELD_NAME = "list"; + static final String TEST_TYPE = "java.util.List"; + static final String OLD_VERSION = "1.2.3"; + static final String NEW_VERSION = "1.3.0"; + static final JApiCmpArchive OLD_ARCHIVE = new JApiCmpArchive(new File("my-old-archive.jar"), OLD_VERSION); + static final JApiCmpArchive NEW_ARCHIVE = new JApiCmpArchive(new File("my-new-archive.jar"), NEW_VERSION); + static final MarkdownMessageOptions MSG = MarkdownOptions.newDefault().message; + + @Test + public void testNoChanges() { + Options options = Options.newDefault(); + options.setOldArchives(singletonList(OLD_ARCHIVE)); + options.setNewArchives(singletonList(NEW_ARCHIVE)); + MarkdownOutputGenerator generator = new MarkdownOutputGenerator(options, emptyList()); + String generated = generator.generate(); + assertThat(generated, containsString(MSG.badgeNoChanges)); + assertThat(generated, containsString( + format(MSG.summaryNoChanges, format(MSG.oneNewVersion, NEW_VERSION), format(MSG.oneOldVersion, OLD_VERSION)))); + } + + @Test + public void testWarningWhenIgnoreMissingClasses() { + Options options = Options.newDefault(); + options.setOldArchives(Arrays.asList(OLD_ARCHIVE, OLD_ARCHIVE)); + options.setNewArchives(Arrays.asList(NEW_ARCHIVE, NEW_ARCHIVE)); + options.setIgnoreMissingClasses(true); + MarkdownOutputGenerator generator = new MarkdownOutputGenerator(options, emptyList()); + String generated = generator.generate(); + assertThat(generated, containsString(MSG.warningAllMissingClassesIgnored)); + assertThat(generated, containsString( + format(MSG.summaryNoChanges, MSG.manyNewArchives, MSG.manyOldArchives))); + } + + @Test + public void testNoClassFileFormatVersionIfInterfaceRemoved() throws Exception { + JarArchiveComparatorOptions jarArchiveComparatorOptions = new JarArchiveComparatorOptions(); + jarArchiveComparatorOptions.setAccessModifier(PRIVATE); + List jApiClasses = ClassesHelper.compareClasses(jarArchiveComparatorOptions, new ClassesHelper.ClassesGenerator() { + @Override + public List createOldClasses(ClassPool classPool) throws Exception { + CtClass myInterface = CtInterfaceBuilder.create() + .name(TEST_INTERFACE_NAME) + .addToClassPool(classPool); + return singletonList(myInterface); + } + + @Override + public List createNewClasses(ClassPool classPool) { + return emptyList(); + } + }); + MarkdownOptions mdOptions = MarkdownOptions.newDefault(); + mdOptions.setTargetOldVersion(OLD_VERSION); + mdOptions.setTargetNewVersion(NEW_VERSION); + mdOptions.options.setOldArchives(Arrays.asList(OLD_ARCHIVE, OLD_ARCHIVE)); + mdOptions.options.setNewArchives(Arrays.asList(NEW_ARCHIVE, NEW_ARCHIVE)); + MarkdownOutputGenerator generator = new MarkdownOutputGenerator(mdOptions, jApiClasses); + String generated = generator.generate(); + assertThat(generated, containsString( + format(MSG.summaryMajorChanges, format(MSG.oneNewVersion, NEW_VERSION), format(MSG.oneOldVersion, OLD_VERSION)))); + Assert.assertFalse(generated.contains("-1.-1")); + } + + @Test + public void testMethodWithGenericTypes() throws Exception { + JarArchiveComparatorOptions jarArchiveComparatorOptions = new JarArchiveComparatorOptions(); + jarArchiveComparatorOptions.setAccessModifier(PRIVATE); + List jApiClasses = ClassesHelper.compareClasses(jarArchiveComparatorOptions, new ClassesHelper.ClassesGenerator() { + @Override + public List createOldClasses(ClassPool classPool) throws Exception { + CtClass ctClass = CtClassBuilder.create() + .name(TEST_CLASS_FQN) + .addToClassPool(classPool); + CtMethod method = CtMethodBuilder.create() + .publicAccess() + .returnType(classPool.get(TEST_TYPE)) + .name(TEST_METHOD_NAME) + .parameter(classPool.get(TEST_TYPE)) + .body(TEST_METHOD_BODY) + .addToClass(ctClass); + method.setGenericSignature("(Ljava/util/List;)Ljava/util/List;"); + return singletonList(ctClass); + } + + @Override + public List createNewClasses(ClassPool classPool) throws Exception { + CtClass ctClass = CtClassBuilder.create() + .name(TEST_CLASS_FQN) + .addToClassPool(classPool); + CtMethod method = CtMethodBuilder.create() + .publicAccess() + .returnType(classPool.get(TEST_TYPE)) + .name(TEST_METHOD_NAME) + .parameter(classPool.get(TEST_TYPE)) + .body(TEST_METHOD_BODY) + .addToClass(ctClass); + method.setGenericSignature("(Ljava/util/List;)Ljava/util/List;"); + return singletonList(ctClass); + } + }); + Options options = Options.newDefault(); + MarkdownOutputGenerator generator = new MarkdownOutputGenerator(options, jApiClasses); + String generated = generator.generate(); + assertThat(generated, containsString(format("\n| %s | [%s] | ![%s] | ![%s] ![%s] |\n", + MSG.statusSourceIncompatible, + TEST_CLASS_FQN, + MSG.serializationCompatibility.get(NOT_SERIALIZABLE), + MSG.compatibilityChangeType.get(METHOD_RETURN_TYPE_GENERICS_CHANGED), + MSG.compatibilityChangeType.get(METHOD_PARAMETER_GENERICS_CHANGED)))); + assertThat(generated, containsString(MSG.expandResults)); + assertThat(generated, containsString(format(MSG.compatibilityBinary, MSG.checked))); + assertThat(generated, containsString(format(MSG.compatibilitySource, MSG.unchecked))); + assertThat(generated, containsString(format(MSG.compatibilitySerialization, MSG.checked))); + } + + @Test + public void testMethodWithGenericTypesReportOnlySummary() throws Exception { + JarArchiveComparatorOptions jarArchiveComparatorOptions = new JarArchiveComparatorOptions(); + jarArchiveComparatorOptions.setAccessModifier(PRIVATE); + List jApiClasses = ClassesHelper.compareClasses(jarArchiveComparatorOptions, new ClassesHelper.ClassesGenerator() { + @Override + public List createOldClasses(ClassPool classPool) throws Exception { + CtClass ctClass = CtClassBuilder.create() + .name(TEST_CLASS_FQN) + .addToClassPool(classPool); + CtMethod method = CtMethodBuilder.create() + .publicAccess() + .returnType(classPool.get(TEST_TYPE)) + .name(TEST_METHOD_NAME) + .parameter(classPool.get(TEST_TYPE)) + .body(TEST_METHOD_BODY) + .addToClass(ctClass); + method.setGenericSignature("(Ljava/util/List;)Ljava/util/List;"); + return singletonList(ctClass); + } + + @Override + public List createNewClasses(ClassPool classPool) throws Exception { + CtClass ctClass = CtClassBuilder.create() + .name(TEST_CLASS_FQN) + .addToClassPool(classPool); + CtMethod method = CtMethodBuilder.create() + .publicAccess() + .returnType(classPool.get(TEST_TYPE)) + .name(TEST_METHOD_NAME) + .parameter(classPool.get(TEST_TYPE)) + .body(TEST_METHOD_BODY) + .addToClass(ctClass); + method.setGenericSignature("(Ljava/util/List;)Ljava/util/List;"); + return singletonList(ctClass); + } + }); + Options options = Options.newDefault(); + options.setReportOnlySummary(true); + MarkdownOutputGenerator generator = new MarkdownOutputGenerator(options, jApiClasses); + String generated = generator.generate(); + assertThat(generated, containsString(format("\n| %s | %s | ![%s] | ![%s] ![%s] |\n", + MSG.statusSourceIncompatible, + TEST_CLASS_FQN, + MSG.serializationCompatibility.get(NOT_SERIALIZABLE), + MSG.compatibilityChangeType.get(METHOD_RETURN_TYPE_GENERICS_CHANGED), + MSG.compatibilityChangeType.get(METHOD_PARAMETER_GENERICS_CHANGED)))); + assertThat(generated, not(containsString(MSG.expandResults))); + assertThat(generated, not(containsString(format(MSG.compatibilityBinary, MSG.checked)))); + assertThat(generated, not(containsString(format(MSG.compatibilitySource, MSG.unchecked)))); + assertThat(generated, not(containsString(format(MSG.compatibilitySerialization, MSG.checked)))); + } + + @Test + public void testMethodWithGenericTypesRemoved() throws Exception { + JarArchiveComparatorOptions jarArchiveComparatorOptions = new JarArchiveComparatorOptions(); + jarArchiveComparatorOptions.setAccessModifier(PRIVATE); + List jApiClasses = ClassesHelper.compareClasses(jarArchiveComparatorOptions, new ClassesHelper.ClassesGenerator() { + @Override + public List createOldClasses(ClassPool classPool) throws Exception { + CtClass ctClass = CtClassBuilder.create() + .name(TEST_CLASS_FQN) + .addToClassPool(classPool); + CtMethod method = CtMethodBuilder.create() + .publicAccess() + .returnType(classPool.get(TEST_TYPE)) + .name(TEST_METHOD_NAME) + .parameter(classPool.get(TEST_TYPE)) + .body(TEST_METHOD_BODY) + .addToClass(ctClass); + method.setGenericSignature("(Ljava/util/List;)Ljava/util/List;"); + return singletonList(ctClass); + } + + @Override + public List createNewClasses(ClassPool classPool) { + CtClass ctClass = CtClassBuilder.create() + .name(TEST_CLASS_FQN) + .addToClassPool(classPool); + return singletonList(ctClass); + } + }); + Options options = Options.newDefault(); + MarkdownOutputGenerator generator = new MarkdownOutputGenerator(options, jApiClasses); + String generated = generator.generate(); + assertThat(generated, containsString(format("\n| %s | [%s] | ![%s] | ![%s] |\n", + MSG.statusModified, + TEST_CLASS_FQN, + MSG.serializationCompatibility.get(NOT_SERIALIZABLE), + MSG.compatibilityChangeType.get(METHOD_REMOVED)))); + assertThat(generated, containsString(format(MSG.compatibilityBinary, MSG.unchecked))); + assertThat(generated, containsString(format(MSG.compatibilitySource, MSG.unchecked))); + assertThat(generated, containsString(format(MSG.compatibilitySerialization, MSG.checked))); + } + + @Test + public void testFieldWithGenericTypes() throws Exception { + JarArchiveComparatorOptions jarArchiveComparatorOptions = new JarArchiveComparatorOptions(); + jarArchiveComparatorOptions.setAccessModifier(PRIVATE); + List jApiClasses = ClassesHelper.compareClasses(jarArchiveComparatorOptions, new ClassesHelper.ClassesGenerator() { + @Override + public List createOldClasses(ClassPool classPool) throws Exception { + CtClass ctClass = CtClassBuilder.create() + .name(TEST_CLASS_FQN) + .addToClassPool(classPool); + CtField ctField = CtFieldBuilder.create() + .type(classPool.get(TEST_TYPE)) + .name(TEST_FIELD_NAME) + .addToClass(ctClass); + ctField.setGenericSignature("Ljava/util/List;"); + return singletonList(ctClass); + } + + @Override + public List createNewClasses(ClassPool classPool) throws Exception { + CtClass ctClass = CtClassBuilder.create() + .name(TEST_CLASS_FQN) + .addToClassPool(classPool); + CtField ctField = CtFieldBuilder.create() + .type(classPool.get(TEST_TYPE)) + .name(TEST_FIELD_NAME) + .addToClass(ctClass); + ctField.setGenericSignature("Ljava/util/List;"); + return singletonList(ctClass); + } + }); + Options options = Options.newDefault(); + MarkdownOutputGenerator generator = new MarkdownOutputGenerator(options, jApiClasses); + String generated = generator.generate(); + assertThat(generated, containsString(format("\n| %s | [%s] | ![%s] | ![%s] |\n", + MSG.statusSourceIncompatible, + TEST_CLASS_FQN, + MSG.serializationCompatibility.get(NOT_SERIALIZABLE), + MSG.compatibilityChangeType.get(FIELD_GENERICS_CHANGED)))); + assertThat(generated, containsString(format(MSG.compatibilityBinary, MSG.checked))); + assertThat(generated, containsString(format(MSG.compatibilitySource, MSG.unchecked))); + assertThat(generated, containsString(format(MSG.compatibilitySerialization, MSG.checked))); + } +} diff --git a/pom.xml b/pom.xml index db8b1dcc4..66b14df86 100644 --- a/pom.xml +++ b/pom.xml @@ -128,6 +128,11 @@ Stefano Cordio https://github.com/scordio + + Guillermo Calvo + https://github.com/guillermocalvo + guillermo@guillermo.dev + diff --git a/src/site/markdown/AntTask.md b/src/site/markdown/AntTask.md index 3e99b7bd1..02962e2d1 100644 --- a/src/site/markdown/AntTask.md +++ b/src/site/markdown/AntTask.md @@ -49,6 +49,7 @@ The following table gives an overview of all available parameters of the Ant tas | classpath | true | n.a. | Classpath for the dependencies used to compare old and new versions. | | classpathref | true | n.a. | Classpath reference for the dependencies used to compare old and new versions. | | semanticVersioning | true | false | Indicate which part of the version to increment according to semantic versioning rules. | +| markdown | true | false | Generates output in Markdown format. | | onlyBinaryIncompatible | true | false | If true, output only binary incompatible changes. | | onlyModified | true | false | If true, output only modified classes/methods, else print all classes and methods.| | includeSynthetic | true | false | If true, track changes for synthetic classes and class members.| diff --git a/src/site/markdown/CliTool.md b/src/site/markdown/CliTool.md index 411111b84..f1808ff5c 100644 --- a/src/site/markdown/CliTool.md +++ b/src/site/markdown/CliTool.md @@ -18,6 +18,7 @@ SYNOPSIS [--old-classpath ] [--report-only-filename] [--report-only-summary] [(-s | --semantic-versioning)] + [--markdown] [(-x | --xml-file )] [--error-on-binary-incompatibility] [--error-on-source-incompatibility] @@ -105,6 +106,9 @@ OPTIONS -s, --semantic-versioning Tells you which part of the version to increment. + --markdown + Generates output in Markdown format. + -x , --xml-file Provides the path to the xml output file. diff --git a/src/site/markdown/Examples.md b/src/site/markdown/Examples.md index d4fdf766f..9523674e6 100644 --- a/src/site/markdown/Examples.md +++ b/src/site/markdown/Examples.md @@ -35,6 +35,11 @@ An example for such a report can be found [here](http://htmlpreview.github.io/?h HTML Report +At your preference, japicmp can generate a [Markdown](https://www.markdownguide.org/) report. +You can see an example [here](https://github.com/siom79/japicmp/blob/master/doc/japicmp_guava.md). + +![Markdown Report](https://raw.github.com/siom79/japicmp/master/doc/japicmp_guava_markdown.png) + You can also let japicmp create an XML report like the following one: ``` diff --git a/src/site/markdown/MavenPlugin.md b/src/site/markdown/MavenPlugin.md index 79e61b739..beb737626 100644 --- a/src/site/markdown/MavenPlugin.md +++ b/src/site/markdown/MavenPlugin.md @@ -97,6 +97,7 @@ The following properties can be set: | japicmp.skip | Skip the execution of this plugin. | | japicmp.skipXmlReport | Skip the generation of the XML report. | | japicmp.skipHtmlReport | Skip the generation of the HTML report. | +| japicmp.skipMarkdownReport | Skip the generation of the Markdown report. | | japicmp.breakBuildOnModifications | Break the build in case of any modifications. | | japicmp.breakBuildOnBinaryIncompatibleModifications | Break the build in case of any binary incompatible modifications. | | japicmp.breakBuildOnSourceIncompatibleModifications | Break the build in case of any source incompatible modifications. | @@ -172,6 +173,7 @@ An advanced configuration can utilize the following parameters: true path/to/stylesheet.css Title of report + Title of report false false false @@ -182,6 +184,7 @@ An advanced configuration can utilize the following parameters: false false false + false false .*incl.* @@ -241,6 +244,7 @@ the <dependency> element. Through the <parameter> element you can pr | excludeExclusively | true | false | Exclude only packages specified in the "excludes" parameter, include their sub-packages. | | htmlStylesheet | true | n.a. | Path to an individual CSS stylesheet for the HTML report. | | htmlTitle | true | n.a. | A title for the HTML report (optional). | +| markdownTitle | true | n.a. | A title for the Markdown report (optional). | | skipPomModules | true | true | Setting this parameter to false (default: true) will not skip execution in modules with packaging type pom. | | skip | true | false | Setting this parameter to true will skip execution of the plugin. | | ignoreNonResolvableArtifacts | true | false | Set this to true in order to ignore artifacts that cannot be resolved, i.e. the build does not break in case a dependency cannot be resolved to a file. | @@ -251,6 +255,7 @@ the <dependency> element. Through the <parameter> element you can pr | postAnalysisScript | true | n.a. | A [Groovy](https://www.groovy-lang.org/) script that gets invoked after analysis is completed and before the output is written. This way it can be used to filter the output or break the build on specific conditions. It can be an absolute path or a relative path of a file within the classpath.| | skipXmlReport | true | false | If set to true, no XML report will be generated. | | skipHtmlReport | true | false | If set to true, no HTML report will be generated. | +| skipMarkdownReport | true | false | If set to true, no Markdown report will be generated. | | skipDiffReport | true | false | If set to true, no diff report will be generated. | | oldVersionPattern | true | n.a. | If <oldVersion> is not used, the old version compared against must match this regular expression. | | includeModules | true | n.a. | List of regular expression that specify if an artifact should be excluded based on its artifact id. | diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md index 9cc11a52b..0355c52d5 100644 --- a/src/site/markdown/index.md +++ b/src/site/markdown/index.md @@ -107,7 +107,7 @@ Features * Comparison of two jar archives without the need to add all of their dependencies to the classpath. * Differences are printed on the command line in a simple diff format. -* Differences can optionally be printed as XML or HTML file. +* Differences can optionally be printed as [Markdown](https://www.markdownguide.org/), XML or HTML file. * Per default private and package protected classes and class members are not compared. If necessary, the access modifier of the classes and class members to be compared can be set to public, protected, package or private. * Per default all classes are tracked. If necessary, certain packages, classes, methods or fields can be excluded or explicitly included. Inclusion and exclusion is also possible based on annotations. @@ -115,6 +115,7 @@ Features * All changes between annotations are compared, hence japicmp can be used to track annotation-based APIs like JAXB, JPA, JAX-RS, etc. * A maven plugin is available that allows you to compare the current artifact version with some older version from the repository. * The option `--semantic-versioning` tells you which part of the version you have to increment in order to follow [semantic versioning](http://semver.org/). +* The option `--markdown` generates output in [Markdown](https://www.markdownguide.org/) format. * If a class is serializable, changes are evaluated regarding the [Java Object Serialization Specification](http://docs.oracle.com/javase/7/docs/platform/serialization/spec/serialTOC.html). * Per default synthetic classes and class members (e.g. [bridge methods](https://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html)) are hidden. They can be listed by using the option `--include-synthetic`. * The maven plugin allows project-specific filtering and reports using a custom [Groovy](groovy-lang.org) script.