Skip to content

Commit

Permalink
fix (core): Consistent hashCode/equals/toString for all Things
Browse files Browse the repository at this point in the history
  • Loading branch information
vorburger committed Jun 23, 2024
1 parent 8ff8f3f commit ac0ee52
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 18 deletions.
2 changes: 2 additions & 0 deletions java/dev/enola/thing/PredicatesObjects.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ public interface PredicatesObjects {
*/
@Nullable String datatype(String predicateIRI);

Map<String, String> datatypes();

@Deprecated // TODO Remove once record Literal is gone
default @Nullable String datatypeLEGACY(String predicateIRI) {
var datatype = datatype(predicateIRI);
Expand Down
38 changes: 38 additions & 0 deletions java/dev/enola/thing/impl/AbstractThing.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2024 The Enola <https://enola.dev> Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.enola.thing.impl;

import dev.enola.thing.Thing;

public abstract class AbstractThing implements Thing {

@Override
public final int hashCode() {
return ThingHashCodeEqualsToString.hashCode(this);
}

@Override
public final boolean equals(Object obj) {
return ThingHashCodeEqualsToString.equals(this, obj);
}

@Override
public final String toString() {
return ThingHashCodeEqualsToString.toString(this);
}
}
3 changes: 3 additions & 0 deletions java/dev/enola/thing/impl/IImmutablePredicatesObjects.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,7 @@ public interface IImmutablePredicatesObjects extends PredicatesObjects {

@Override
ImmutableSet<String> predicateIRIs();

@Override
ImmutableMap<String, String> datatypes();
}
1 change: 1 addition & 0 deletions java/dev/enola/thing/impl/ImmutablePredicatesObjects.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public ImmutableSet<String> predicateIRIs() {
return (T) properties.get(predicateIRI);
}

@Override
public ImmutableMap<String, String> datatypes() {
return datatypes;
}
Expand Down
17 changes: 3 additions & 14 deletions java/dev/enola/thing/impl/ImmutableThing.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
*/
package dev.enola.thing.impl;

import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableMap;
import com.google.errorprone.annotations.Immutable;
import com.google.errorprone.annotations.ThreadSafe;
Expand Down Expand Up @@ -60,27 +59,17 @@ public String iri() {

@Override
public boolean equals(Object obj) {
if (obj == this) return true;
// NO NEED: if (obj == null) return false;
// NOT: if (getClass() != obj.getClass()) return false;
if (!(obj instanceof ImmutableThing other)) return false;
return Objects.equals(this.iri, other.iri)
&& Objects.equals(this.properties(), other.properties())
&& Objects.equals(this.datatypes(), other.datatypes());
return ThingHashCodeEqualsToString.equals(this, obj);
}

@Override
public int hashCode() {
return Objects.hash(iri, properties(), datatypes());
return ThingHashCodeEqualsToString.hashCode(this);
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("iri", iri)
.add("properties", properties())
.add("datatypes", datatypes())
.toString();
return ThingHashCodeEqualsToString.toString(this);
}

@Override
Expand Down
12 changes: 11 additions & 1 deletion java/dev/enola/thing/impl/MutableThing.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

import dev.enola.thing.Thing;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

import org.jspecify.annotations.Nullable;

import java.util.HashMap;
Expand All @@ -35,7 +37,10 @@
*
* <p>This implementation is not thread safe, obviously.
*/
public class MutableThing<B extends MutableThing> implements Thing, Thing.Builder<B> {
@SuppressFBWarnings("EQ_DOESNT_OVERRIDE_EQUALS")
// skipcq: JAVA-W0100
public class MutableThing<B extends MutableThing> extends AbstractThing
implements Thing, Thing.Builder<B> {

protected @Nullable String iri;
protected final Map<String, Object> properties;
Expand Down Expand Up @@ -95,6 +100,11 @@ public Set<String> predicateIRIs() {
return datatypes.get(predicateIRI);
}

@Override
public Map<String, String> datatypes() {
return datatypes;
}

@Override
public Builder<? extends Thing> copy() {
return this;
Expand Down
11 changes: 10 additions & 1 deletion java/dev/enola/thing/impl/OnlyIRIThing.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,14 @@

import dev.enola.thing.Thing;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

import org.jspecify.annotations.Nullable;

/** {@link Thing} with only an IRI and no properties (optimized). */
public class OnlyIRIThing implements IImmutableThing {
@SuppressFBWarnings("EQ_DOESNT_OVERRIDE_EQUALS")
// skipcq: JAVA-W0100
public class OnlyIRIThing extends AbstractThing implements IImmutableThing {
private final String iri;

public OnlyIRIThing(String iri) {
Expand All @@ -52,6 +56,11 @@ public ImmutableSet<String> predicateIRIs() {
return null;
}

@Override
public ImmutableMap<String, String> datatypes() {
return ImmutableMap.of();
}

@Override
public <T> @Nullable T get(String predicateIRI) {
return null;
Expand Down
51 changes: 51 additions & 0 deletions java/dev/enola/thing/impl/ThingHashCodeEqualsToString.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2024 The Enola <https://enola.dev> Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.enola.thing.impl;

import com.google.common.base.MoreObjects;

import dev.enola.thing.Thing;

import java.util.Objects;

final class ThingHashCodeEqualsToString {

static boolean equals(Thing thiz, Object obj) {
if (obj == thiz) return true;
// NO NEED: if (obj == null) return false;
// NOT: if (getClass() != obj.getClass()) return false;
if (!(obj instanceof Thing other)) return false;
return Objects.equals(thiz.iri(), other.iri())
&& Objects.equals(thiz.properties(), other.properties())
&& Objects.equals(thiz.datatypes(), other.datatypes());
}

static int hashCode(Thing thiz) {
return Objects.hash(thiz.iri(), thiz.properties(), thiz.datatypes());
}

static String toString(Thing thiz) {
return MoreObjects.toStringHelper(thiz)
.add("iri", thiz.iri())
.add("properties", thiz.properties())
.add("datatypes", thiz.datatypes())
.toString();
}

private ThingHashCodeEqualsToString() {}
}
12 changes: 11 additions & 1 deletion java/dev/enola/thing/java/DelegatingThing.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,19 @@
package dev.enola.thing.java;

import dev.enola.thing.Thing;
import dev.enola.thing.impl.AbstractThing;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

import org.jspecify.annotations.Nullable;

import java.util.Map;
import java.util.Optional;
import java.util.Set;

public abstract class DelegatingThing implements Thing {
@SuppressFBWarnings("EQ_DOESNT_OVERRIDE_EQUALS")
// skipcq: JAVA-W0100
public abstract class DelegatingThing extends AbstractThing implements Thing {

private final Thing delegate;

Expand All @@ -48,6 +53,11 @@ public Set<String> predicateIRIs() {
return delegate.predicateIRIs();
}

@Override
public Map<String, String> datatypes() {
return delegate.datatypes();
}

@Override
@Nullable
public String datatype(String predicateIRI) {
Expand Down
12 changes: 12 additions & 0 deletions java/dev/enola/thing/message/ThingAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.Objects;
import java.util.Set;

Expand Down Expand Up @@ -89,6 +90,17 @@ public ImmutableMap<String, Object> properties() {
return builder.build();
}

@Override
public Map<String, String> datatypes() {
var predicateIRIs = predicateIRIs();
var builder = ImmutableMap.<String, String>builderWithExpectedSize(predicateIRIs.size());
for (var predicateIRI : predicateIRIs) {
var datatype = datatype(predicateIRI);
if (datatype != null) builder.put(predicateIRI, datatype);
}
return builder.build();
}

@Override
public String datatype(String predicateIRI) {
var value = proto.getFieldsMap().get(predicateIRI);
Expand Down
2 changes: 1 addition & 1 deletion java/dev/enola/thing/repo/ThingRepositoriesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

public class ThingRepositoriesTest {

public static Thing TEST_THING =
public static final Thing TEST_THING =
ImmutableThing.builder()
.iri("http://example.com")
.set("http://example.com/message", "hello")
Expand Down

0 comments on commit ac0ee52

Please sign in to comment.