JDK 13 Compatibility (#116)

* Add jdk 13 to build matrix

* Adjust indentation

* Adjust indentation

* Bump kemitix-maven-tiles from 1.2.0 to 2.4.1

* Fix TypeAlias.equals(Object) does not check for null argument

net.kemitix.mon.TypeAlias.equals(Object) does not check for null argument [net.kemitix.mon.TypeAlias] At TypeAlias.java:[lines 82-88] NP_EQUALS_SHOULD_HANDLE_NULL_ARGUMENT

* Fix TypeAlias.flatMap(Function) declares unbound method template parameter

[ERROR] Method net.kemitix.mon.TypeAlias.flatMap(Function) declares unbound method template parameter(s) [net.kemitix.mon.TypeAlias] At TypeAlias.java:[line 72] UMTP_UNBOUND_METHOD_TEMPLATE_PARAMETER

* Fix Lazy has a circular dependency with other classes

[ERROR] Class net.kemitix.mon.lazy.Lazy has a circular dependency with other classes [net.kemitix.mon.lazy.Lazy] At Lazy.java:[lines 36-46] FCCD_FIND_CLASS_CIRCULAR_DEPENDENCY

* Fix Synchronization performed on AtomicReference

[ERROR] Synchronization performed on java.util.concurrent.atomic.AtomicReference in net.kemitix.mon.lazy.LazySupplier.value() [net.kemitix.mon.lazy.LazySupplier] At LazySupplier.java:[line 61] JLM_JSR166_UTILCONCURRENT_MONITORENTER

* Fix Just.orElseThrow(Supplier) declares throwing an exception that isn't thrown

[ERROR] Non derivable method net.kemitix.mon.maybe.Just.orElseThrow(Supplier) declares throwing an exception that isn't thrown [net.kemitix.mon.maybe.Just] At Just.java:[line 102] BED_BOGUS_EXCEPTION_DECLARATION

* Fix Maybe has a circular dependency with other classes

[ERROR] Class net.kemitix.mon.maybe.Maybe has a circular dependency with other classes [net.kemitix.mon.maybe.Maybe] At Maybe.java:[lines 40-94] FCCD_FIND_CLASS_CIRCULAR_DEPENDENCY

* Fix Maybe.findFirst(Stream) uses immediate execution of a block

[ERROR] Method net.kemitix.mon.maybe.Maybe.findFirst(Stream) uses immediate execution of a block of code that is often not used [net.kemitix.mon.maybe.Maybe] At Maybe.java:[line 94] OI_OPTIONAL_ISSUES_USES_IMMEDIATE_EXECUTION

* Fix Success/Result/Err has a circular dependency

[ERROR] Class net.kemitix.mon.result.Err has a circular dependency with other classes [net.kemitix.mon.result.Err] At Err.java: FCCD_FIND_CLASS_CIRCULAR_DEPENDENCY

* Fix GeneralisedTree has a circular dependency

[ERROR] Class net.kemitix.mon.tree.GeneralisedTree has a circular dependency with other classes [net.kemitix.mon.tree.GeneralisedTree] At GeneralisedTree.java:[lines 39-80] FCCD_FIND_CLASS_CIRCULAR_DEPENDENCY

* Supress warning about boxing a boolean

NAB_NEEDLESS_BOOLEAN_CONSTANT_CONVERSION

Without creating a whole reimplemention of Maybe/Just/Nothing purely for `boolean` primitives, we can’t avoid this boxing.

* Supress store before return warnings in Lombok generate hashCode

USBR_UNNECESSARY_STORE_BEFORE_RETURN

The annotation has to be used at the class level, which unfortunately means we have no store-before-return checks for the rest of the class.

* Suppress warning about unused parameter

The type parameter for `Tree.builder(type)` is used to specify the parameterised type of the return value.

* Checkstyle fixups

* [changelog] updated
This commit is contained in:
Paul Campbell 2020-03-20 07:17:29 +00:00 committed by GitHub
parent 86d3a214ed
commit 830b312d9e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 120 additions and 45 deletions

View file

@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
java: [ 8, 11 ] java: [ 8, 11, 13 ]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Set up JDK ${{ matrix.java }} - name: Set up JDK ${{ matrix.java }}

View file

@ -10,9 +10,11 @@ The format is based on [[https://keepachangelog.com/en/1.0.0/][Keep a Changelog]
** Added ** Added
* Add github actions config (#113) * Add github actions config (#113)
* Add JDK 13 compatibility (#116)
** Dependencies ** Dependencies
* Bump kemitix-maven-tiles from 1.2.0 to 2.4.1 (#116)
* Bump assertj-core from 3.13.2 to 3.15.0 (#106) * Bump assertj-core from 3.13.2 to 3.15.0 (#106)
* Bump junit-bom from 5.5.2 to 5.6.0 (#105) * Bump junit-bom from 5.5.2 to 5.6.0 (#105)
* Bump tiles-maven-plugin from 2.15 to 2.16 (#101) * Bump tiles-maven-plugin from 2.15 to 2.16 (#101)

View file

@ -38,11 +38,12 @@
<assertj.version>3.15.0</assertj.version> <assertj.version>3.15.0</assertj.version>
<lombok.version>1.18.12</lombok.version> <lombok.version>1.18.12</lombok.version>
<tiles-maven-plugin.version>2.16</tiles-maven-plugin.version> <tiles-maven-plugin.version>2.16</tiles-maven-plugin.version>
<kemitix-maven-tiles.version>1.2.0</kemitix-maven-tiles.version> <kemitix-maven-tiles.version>2.4.1</kemitix-maven-tiles.version>
<digraph-dependency.basePackage>net.kemitix.mon</digraph-dependency.basePackage> <digraph-dependency.basePackage>net.kemitix.mon</digraph-dependency.basePackage>
<kemitix-checkstyle.version>5.0.0</kemitix-checkstyle.version> <kemitix-checkstyle.version>5.0.0</kemitix-checkstyle.version>
<pitest-maven-plugin.version>1.5.0</pitest-maven-plugin.version> <pitest-maven-plugin.version>1.5.0</pitest-maven-plugin.version>
<pitest-junit5-plugin.version>0.12</pitest-junit5-plugin.version> <pitest-junit5-plugin.version>0.12</pitest-junit5-plugin.version>
<spotbugs.version>4.0.1</spotbugs.version>
</properties> </properties>
<dependencies> <dependencies>
@ -75,6 +76,12 @@
<version>${assertj.version}</version> <version>${assertj.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-annotations</artifactId>
<version>${spotbugs.version}</version>
<scope>provided</scope>
</dependency>
</dependencies> </dependencies>
<dependencyManagement> <dependencyManagement>

View file

@ -64,11 +64,10 @@ public abstract class TypeAlias<T> {
* Map the TypeAlias into another TypeAlias. * Map the TypeAlias into another TypeAlias.
* *
* @param f the function to create the new value * @param f the function to create the new value
* @param <R> the type of the new value within a TypeAlias
* @param <U> the type of the TypeAlias superclass containing the new value * @param <U> the type of the TypeAlias superclass containing the new value
* @return a TypeAlias * @return a TypeAlias
*/ */
public final <R, U extends TypeAlias<R>> U flatMap(final Function<T, U> f) { public final <U extends TypeAlias<?>> U flatMap(final Function<T, U> f) {
return f.apply(value); return f.apply(value);
} }
@ -85,7 +84,7 @@ public abstract class TypeAlias<T> {
return otherValueClass.equals(getValue().getClass()) return otherValueClass.equals(getValue().getClass())
&& other.value.equals(getValue()); && other.value.equals(getValue());
} }
return map(o::equals); return o != null && map(o::equals);
} }
@Override @Override

View file

@ -38,6 +38,7 @@ class LazySupplier<T> implements Lazy<T> {
private final Supplier<T> supplier; private final Supplier<T> supplier;
private final AtomicBoolean evaluated = new AtomicBoolean(false); private final AtomicBoolean evaluated = new AtomicBoolean(false);
private final AtomicReference<T> value = new AtomicReference<>(); private final AtomicReference<T> value = new AtomicReference<>();
private final Object lock = new Object();
/** /**
* Creates a new Lazy wrapper for the Supplier. * Creates a new Lazy wrapper for the Supplier.
@ -58,7 +59,7 @@ class LazySupplier<T> implements Lazy<T> {
if (evaluated.get()) { if (evaluated.get()) {
return value.get(); return value.get();
} }
synchronized (value) { synchronized (lock) {
if (!evaluated.get()) { if (!evaluated.get()) {
value.set(supplier.get()); value.set(supplier.get());
evaluated.set(true); evaluated.set(true);
@ -69,7 +70,7 @@ class LazySupplier<T> implements Lazy<T> {
@Override @Override
public <R> Lazy<R> map(final Function<T, R> f) { public <R> Lazy<R> map(final Function<T, R> f) {
return Lazy.of(() -> f.apply(value())); return new LazySupplier<R>(() -> f.apply(value()));
} }
} }

View file

@ -85,11 +85,12 @@ final class Just<T> implements Maybe<T> {
} }
@Override @Override
@SuppressWarnings("unchecked")
public Maybe<T> filter(final Predicate<T> predicate) { public Maybe<T> filter(final Predicate<T> predicate) {
if (predicate.test(value)) { if (predicate.test(value)) {
return this; return this;
} }
return Maybe.nothing(); return (Maybe<T>) Nothing.INSTANCE;
} }
@Override @Override
@ -98,7 +99,7 @@ final class Just<T> implements Maybe<T> {
} }
@Override @Override
public <X extends Throwable> T orElseThrow(final Supplier<? extends X> e) throws X { public <X extends Throwable> T orElseThrow(final Supplier<? extends X> e) {
return value; return value;
} }

View file

@ -91,7 +91,7 @@ public interface Maybe<T> extends Functor<T, Maybe<?>> {
public static <T> Maybe<T> findFirst(Stream<T> stream) { public static <T> Maybe<T> findFirst(Stream<T> stream) {
return stream.findFirst() return stream.findFirst()
.map(Maybe::just) .map(Maybe::just)
.orElse(Maybe.nothing()); .orElseGet(Maybe::nothing);
} }
/** /**

View file

@ -50,8 +50,9 @@ final class Nothing<T> implements Maybe<T> {
} }
@Override @Override
@SuppressWarnings("unchecked")
public <R> Maybe<R> flatMap(final Function<T, Maybe<R>> f) { public <R> Maybe<R> flatMap(final Function<T, Maybe<R>> f) {
return Maybe.nothing(); return (Maybe<R>) INSTANCE;
} }
@Override @Override

View file

@ -54,12 +54,12 @@ class Err<T> implements Result<T> {
@Override @Override
public <R> Result<R> flatMap(final Function<T, Result<R>> f) { public <R> Result<R> flatMap(final Function<T, Result<R>> f) {
return Result.error(error); return err(error);
} }
@Override @Override
public <R> Result<R> map(final Function<T, R> f) { public <R> Result<R> map(final Function<T, R> f) {
return Result.error(error); return err(error);
} }
@Override @Override
@ -69,7 +69,7 @@ class Err<T> implements Result<T> {
@Override @Override
public Result<Maybe<T>> maybe(final Predicate<T> predicate) { public Result<Maybe<T>> maybe(final Predicate<T> predicate) {
return Result.error(error); return err(error);
} }
@Override @Override
@ -108,7 +108,7 @@ class Err<T> implements Result<T> {
@Override @Override
public <R> Result<R> andThen(final Function<T, Callable<R>> f) { public <R> Result<R> andThen(final Function<T, Callable<R>> f) {
return Result.error(error); return err(error);
} }
@Override @Override
@ -118,7 +118,7 @@ class Err<T> implements Result<T> {
@Override @Override
public Result<T> reduce(final Result<T> identify, final BinaryOperator<T> operator) { public Result<T> reduce(final Result<T> identify, final BinaryOperator<T> operator) {
return Result.error(error); return this;
} }
@Override @Override

View file

@ -49,6 +49,17 @@ public interface Result<T> extends Functor<T, Result<?>> {
.orElseGet(() -> Result.error(error.get())); .orElseGet(() -> Result.error(error.get()));
} }
/**
* Create a Result for an error.
*
* @param error the error (Throwable)
* @param <T> the type had the result been a success
* @return an error Result
*/
public default <T> Result<T> err(final Throwable error) {
return new Err<>(error);
}
/** /**
* Create a Result for an error. * Create a Result for an error.
* *
@ -60,6 +71,22 @@ public interface Result<T> extends Functor<T, Result<?>> {
return new Err<>(error); return new Err<>(error);
} }
/**
* Create a Result for a output of the Callable.
*
* @param callable the callable to produce the result
* @param <T> the type of the value
* @return a Result
*/
@SuppressWarnings("illegalcatch")
public default <T> Result<T> result(final Callable<T> callable) {
try {
return Result.ok(callable.call());
} catch (final Exception e) {
return Result.error(e);
}
}
/** /**
* Create a Result for a output of the Callable. * Create a Result for a output of the Callable.
* *
@ -76,6 +103,17 @@ public interface Result<T> extends Functor<T, Result<?>> {
} }
} }
/**
* Create a Result for a success.
*
* @param value the value
* @param <T> the type of the value
* @return a successful Result
*/
public default <T> Result<T> success(final T value) {
return new Success<>(value);
}
/** /**
* Create a Result for a success. * Create a Result for a success.
* *

View file

@ -54,7 +54,7 @@ class Success<T> implements Result<T> {
@Override @Override
public <R> Result<R> map(final Function<T, R> f) { public <R> Result<R> map(final Function<T, R> f) {
return Result.ok(f.apply(value)); return success(f.apply(value));
} }
@Override @Override
@ -65,9 +65,9 @@ class Success<T> implements Result<T> {
@Override @Override
public Result<Maybe<T>> maybe(final Predicate<T> predicate) { public Result<Maybe<T>> maybe(final Predicate<T> predicate) {
if (predicate.test(value)) { if (predicate.test(value)) {
return Result.ok(Maybe.just(value)); return success(Maybe.just(value));
} }
return Result.ok(Maybe.nothing()); return success(Maybe.nothing());
} }
@Override @Override
@ -103,7 +103,7 @@ class Success<T> implements Result<T> {
@Override @Override
public <R> Result<R> andThen(final Function<T, Callable<R>> f) { public <R> Result<R> andThen(final Function<T, Callable<R>> f) {
return Result.of(f.apply(value)); return result(f.apply(value));
} }
@Override @Override
@ -113,7 +113,7 @@ class Success<T> implements Result<T> {
@Override @Override
public Result<T> reduce(final Result<T> identity, final BinaryOperator<T> operator) { public Result<T> reduce(final Result<T> identity, final BinaryOperator<T> operator) {
return flatMap(a -> identity.flatMap(b -> Result.of(() -> operator.apply(a, b)))); return flatMap(a -> identity.flatMap(b -> result(() -> operator.apply(a, b))));
} }
@Override @Override

View file

@ -21,6 +21,7 @@
package net.kemitix.mon.tree; package net.kemitix.mon.tree;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import net.kemitix.mon.maybe.Maybe; import net.kemitix.mon.maybe.Maybe;
@ -36,6 +37,7 @@ import java.util.function.Function;
* *
* @author Paul Campbell (pcampbell@kemitix.net) * @author Paul Campbell (pcampbell@kemitix.net)
*/ */
@SuppressFBWarnings("USBR_UNNECESSARY_STORE_BEFORE_RETURN")
@EqualsAndHashCode @EqualsAndHashCode
class GeneralisedTree<T> implements Tree<T>, TreeMapper<T> { class GeneralisedTree<T> implements Tree<T>, TreeMapper<T> {
@ -62,7 +64,7 @@ class GeneralisedTree<T> implements Tree<T>, TreeMapper<T> {
*/ */
@Override @Override
public <R> Tree<R> map(final Function<T, R> f) { public <R> Tree<R> map(final Function<T, R> f) {
return Tree.of(f.apply(item), mapTrees(f, subTrees())); return new GeneralisedTree<>(f.apply(item), mapTrees(f, subTrees()));
} }
@Override @Override

View file

@ -21,6 +21,7 @@
package net.kemitix.mon.tree; package net.kemitix.mon.tree;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import net.kemitix.mon.maybe.Maybe; import net.kemitix.mon.maybe.Maybe;
@ -37,6 +38,7 @@ import java.util.stream.Collectors;
* *
* @author Paul Campbell (pcampbell@kemitix.net) * @author Paul Campbell (pcampbell@kemitix.net)
*/ */
@SuppressFBWarnings("USBR_UNNECESSARY_STORE_BEFORE_RETURN")
@EqualsAndHashCode @EqualsAndHashCode
@SuppressWarnings("methodcount") @SuppressWarnings("methodcount")
class MutableTree<T> implements Tree<T>, TreeMapper<T> { class MutableTree<T> implements Tree<T>, TreeMapper<T> {

View file

@ -21,6 +21,7 @@
package net.kemitix.mon.tree; package net.kemitix.mon.tree;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import net.kemitix.mon.maybe.Maybe; import net.kemitix.mon.maybe.Maybe;
import java.util.function.Function; import java.util.function.Function;
@ -84,8 +85,14 @@ class MutableTreeBuilder<T> implements TreeBuilder<T> {
.map(Tree::builder)); .map(Tree::builder));
} }
private Boolean matchesItem(final T childItem, final MutableTree<T> tree) { @SuppressFBWarnings("NAB_NEEDLESS_BOOLEAN_CONSTANT_CONVERSION")
return tree.item().map(childItem::equals).orElse(false); private boolean matchesItem(
final T childItem,
final MutableTree<T> tree
) {
return tree.item()
.map(childItem::equals)
.orElse(false);
} }
} }

View file

@ -21,6 +21,7 @@
package net.kemitix.mon.tree; package net.kemitix.mon.tree;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import net.kemitix.mon.Functor; import net.kemitix.mon.Functor;
import net.kemitix.mon.maybe.Maybe; import net.kemitix.mon.maybe.Maybe;
@ -70,6 +71,8 @@ public interface Tree<T> extends Functor<T, Tree<?>> {
* *
* @return a TreeBuilder * @return a TreeBuilder
*/ */
@SuppressFBWarnings(value = "UP_UNUSED_PARAMETER",
justification = "Use the type parameter to fingerprint the return type")
public static <B> TreeBuilder<B> builder(final Class<B> type) { public static <B> TreeBuilder<B> builder(final Class<B> type) {
return new MutableTreeBuilder<>(); return new MutableTreeBuilder<>();
} }

View file

@ -1,6 +1,7 @@
package net.kemitix.mon; package net.kemitix.mon;
import org.assertj.core.util.Strings; import org.assertj.core.util.Strings;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.Arrays; import java.util.Arrays;
@ -116,6 +117,17 @@ class TypeAliasTest {
assertThat(value).isEqualTo("'text'"); assertThat(value).isEqualTo("'text'");
} }
@Test
@DisplayName("equals other is null then not equals")
void whenOtherNullEqualsIsFalse() {
//given
final AnAlias anAlias = AnAlias.of("text");
//then
boolean result = anAlias.equals(null);
//then
assertThat(result).isFalse();
}
private static class AnAlias extends TypeAlias<String> { private static class AnAlias extends TypeAlias<String> {
/** /**