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,12 +14,12 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
java: [ 8, 11 ]
java: [ 8, 11, 13 ]
steps:
- uses: actions/checkout@v2
- name: Set up JDK ${{ matrix.java }}
uses: actions/setup-java@v1
with:
java-version: ${{ matrix.java }}
- name: Build with Maven
run: mvn -B install
- uses: actions/checkout@v2
- name: Set up JDK ${{ matrix.java }}
uses: actions/setup-java@v1
with:
java-version: ${{ matrix.java }}
- name: Build with Maven
run: mvn -B install

View file

@ -8,17 +8,17 @@ jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Build with Maven
run: mvn -B install
- name: Nexus Repo Publish
run: sh .github/deploy.sh
env:
NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }}
NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }}
GPG_KEYNAME: ${{ secrets.GPG_KEYNAME }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Build with Maven
run: mvn -B install
- name: Nexus Repo Publish
run: sh .github/deploy.sh
env:
NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }}
NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }}
GPG_KEYNAME: ${{ secrets.GPG_KEYNAME }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}

View file

@ -10,9 +10,11 @@ The format is based on [[https://keepachangelog.com/en/1.0.0/][Keep a Changelog]
** Added
* Add github actions config (#113)
* Add JDK 13 compatibility (#116)
** 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 junit-bom from 5.5.2 to 5.6.0 (#105)
* Bump tiles-maven-plugin from 2.15 to 2.16 (#101)

View file

@ -38,11 +38,12 @@
<assertj.version>3.15.0</assertj.version>
<lombok.version>1.18.12</lombok.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>
<kemitix-checkstyle.version>5.0.0</kemitix-checkstyle.version>
<pitest-maven-plugin.version>1.5.0</pitest-maven-plugin.version>
<pitest-junit5-plugin.version>0.12</pitest-junit5-plugin.version>
<spotbugs.version>4.0.1</spotbugs.version>
</properties>
<dependencies>
@ -75,6 +76,12 @@
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-annotations</artifactId>
<version>${spotbugs.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<dependencyManagement>

View file

@ -64,11 +64,10 @@ public abstract class TypeAlias<T> {
* Map the TypeAlias into another TypeAlias.
*
* @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
* @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);
}
@ -85,7 +84,7 @@ public abstract class TypeAlias<T> {
return otherValueClass.equals(getValue().getClass())
&& other.value.equals(getValue());
}
return map(o::equals);
return o != null && map(o::equals);
}
@Override

View file

@ -38,6 +38,7 @@ class LazySupplier<T> implements Lazy<T> {
private final Supplier<T> supplier;
private final AtomicBoolean evaluated = new AtomicBoolean(false);
private final AtomicReference<T> value = new AtomicReference<>();
private final Object lock = new Object();
/**
* Creates a new Lazy wrapper for the Supplier.
@ -58,7 +59,7 @@ class LazySupplier<T> implements Lazy<T> {
if (evaluated.get()) {
return value.get();
}
synchronized (value) {
synchronized (lock) {
if (!evaluated.get()) {
value.set(supplier.get());
evaluated.set(true);
@ -69,7 +70,7 @@ class LazySupplier<T> implements Lazy<T> {
@Override
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
@SuppressWarnings("unchecked")
public Maybe<T> filter(final Predicate<T> predicate) {
if (predicate.test(value)) {
return this;
}
return Maybe.nothing();
return (Maybe<T>) Nothing.INSTANCE;
}
@Override
@ -98,7 +99,7 @@ final class Just<T> implements Maybe<T> {
}
@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;
}

View file

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

View file

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

View file

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

View file

@ -49,6 +49,17 @@ public interface Result<T> extends Functor<T, Result<?>> {
.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.
*
@ -60,6 +71,22 @@ public interface Result<T> extends Functor<T, Result<?>> {
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.
*
@ -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.
*

View file

@ -54,7 +54,7 @@ class Success<T> implements Result<T> {
@Override
public <R> Result<R> map(final Function<T, R> f) {
return Result.ok(f.apply(value));
return success(f.apply(value));
}
@Override
@ -65,9 +65,9 @@ class Success<T> implements Result<T> {
@Override
public Result<Maybe<T>> maybe(final Predicate<T> predicate) {
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
@ -103,7 +103,7 @@ class Success<T> implements Result<T> {
@Override
public <R> Result<R> andThen(final Function<T, Callable<R>> f) {
return Result.of(f.apply(value));
return result(f.apply(value));
}
@Override
@ -113,7 +113,7 @@ class Success<T> implements Result<T> {
@Override
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

View file

@ -21,6 +21,7 @@
package net.kemitix.mon.tree;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import lombok.EqualsAndHashCode;
import net.kemitix.mon.maybe.Maybe;
@ -36,6 +37,7 @@ import java.util.function.Function;
*
* @author Paul Campbell (pcampbell@kemitix.net)
*/
@SuppressFBWarnings("USBR_UNNECESSARY_STORE_BEFORE_RETURN")
@EqualsAndHashCode
class GeneralisedTree<T> implements Tree<T>, TreeMapper<T> {
@ -62,7 +64,7 @@ class GeneralisedTree<T> implements Tree<T>, TreeMapper<T> {
*/
@Override
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

View file

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

View file

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

View file

@ -1,6 +1,7 @@
package net.kemitix.mon;
import org.assertj.core.util.Strings;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
@ -116,6 +117,17 @@ class TypeAliasTest {
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> {
/**