Skip to content

Commit

Permalink
clean(core): Split out MutablePredicatesObjects from MutableThing
Browse files Browse the repository at this point in the history
  • Loading branch information
vorburger committed Sep 29, 2024
1 parent f188146 commit aa9c6db
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 45 deletions.
1 change: 1 addition & 0 deletions java/dev/enola/thing/PredicatesObjects.java
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ default <T extends Thing> Iterable<T> getThings(HasPredicateIRI predicateIRI, Cl

// TODO get... other types.

@Deprecated
Builder<? extends PredicatesObjects> copy();

@SuppressFBWarnings("NM_SAME_SIMPLE_NAME_AS_INTERFACE")
Expand Down
139 changes: 139 additions & 0 deletions java/dev/enola/thing/impl/MutablePredicatesObjects.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* 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.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;

import dev.enola.thing.PredicatesObjects;
import dev.enola.thing.Thing;

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

import org.jspecify.annotations.Nullable;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

@SuppressFBWarnings("EQ_DOESNT_OVERRIDE_EQUALS")
// skipcq: JAVA-W0100
public class MutablePredicatesObjects<B extends IImmutablePredicatesObjects>
implements PredicatesObjects, PredicatesObjects.Builder<B> {

protected @Nullable String iri;
protected final Map<String, Object> properties;
protected final Map<String, String> datatypes;

public MutablePredicatesObjects() {
properties = new HashMap<>();
datatypes = new HashMap<>();
}

public MutablePredicatesObjects(int expectedSize) {
properties = new HashMap<>(expectedSize); // exact
datatypes = new HashMap<>(expectedSize); // upper bound
}

@Override
public Builder<B> set(String predicateIRI, Object value) {
properties.put(predicateIRI, value);
return this;
}

@Override
public Builder<B> set(String predicateIRI, Object value, @Nullable String datatypeIRI) {
properties.put(predicateIRI, value);
if (datatypeIRI != null) datatypes.put(predicateIRI, datatypeIRI);
return this;
}

@Override
@Deprecated
@SuppressWarnings("unchecked")
public <T> @Nullable T get(String predicateIRI) {
return (T) properties.get(predicateIRI);
}

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

@Override
public Set<String> predicateIRIs() {
return properties.keySet();
}

@Override
public @Nullable String datatype(String predicateIRI) {
return datatypes.get(predicateIRI);
}

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

@Override
@Deprecated
public Builder<? extends PredicatesObjects> copy() {
return this;
}

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

@Override
@SuppressWarnings({"EqualsWhichDoesntCheckParameterClass", "EqualsDoesntCheckParameterClass"})
public boolean equals(Object obj) {
return ThingHashCodeEqualsToString.equals(this, obj);
}

@Override
public String toString() {
return ThingHashCodeEqualsToString.toString(this);
}

@Override
@SuppressWarnings("unchecked") // TODO How to remove (B) type cast?!
public B build() {
var immutableBuilder =
ImmutablePredicatesObjects.builderWithExpectedSize(properties.size());
deepBuildInto(immutableBuilder);
return (B) immutableBuilder.build();
}

@SuppressWarnings("Immutable") // TODO This (tries to...) make deep copies of all objects...
protected void deepBuildInto(
PredicatesObjects.Builder<? extends ImmutablePredicatesObjects> immutableBuilder) {
for (Map.Entry<String, Object> entry : properties.entrySet()) {
var predicateIRI = entry.getKey();
var object = entry.getValue();
if (object instanceof List<?> list) object = ImmutableList.copyOf(list);
if (object instanceof Set<?> list) object = ImmutableSet.copyOf(list);
if (object instanceof Thing) throw new IllegalStateException(object.toString());
if (object instanceof MutablePredicatesObjects<?> mutablePredicatesObjects)
object = mutablePredicatesObjects.build();
immutableBuilder.set(predicateIRI, object, datatype(predicateIRI));
}
}
}
62 changes: 19 additions & 43 deletions java/dev/enola/thing/impl/MutableThing.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@

import org.jspecify.annotations.Nullable;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
* Implementation of {@link Thing} and its {@link Thing.Builder} which is simple and mutable.
*
Expand All @@ -39,25 +35,21 @@
*/
@SuppressFBWarnings("EQ_DOESNT_OVERRIDE_EQUALS")
// skipcq: JAVA-W0100
public class MutableThing<B extends IImmutableThing> extends AbstractThing
public class MutableThing<B extends IImmutableThing> extends MutablePredicatesObjects<B>
implements Thing, Thing.Builder<B> {

protected @Nullable String iri;
protected final Map<String, Object> properties;
protected final Map<String, String> datatypes;

public MutableThing() {
properties = new HashMap<>();
datatypes = new HashMap<>();
super();
}

public MutableThing(int expectedSize) {
properties = new HashMap<>(expectedSize); // exact
datatypes = new HashMap<>(expectedSize); // upper bound
super(expectedSize);
}

@Override
public Builder<B> iri(String iri) {
public Thing.Builder<B> iri(String iri) {
this.iri = iri;
return this;
}
Expand All @@ -69,61 +61,45 @@ public String iri() {
}

@Override
public Builder<B> set(String predicateIRI, Object value) {
properties.put(predicateIRI, value);
public Thing.Builder<B> set(String predicateIRI, Object value) {
super.set(predicateIRI, value);
return this;
}

@Override
public Builder<B> set(String predicateIRI, Object value, @Nullable String datatypeIRI) {
properties.put(predicateIRI, value);
if (datatypeIRI != null) datatypes.put(predicateIRI, datatypeIRI);
public Thing.Builder<B> set(String predicateIRI, Object value, @Nullable String datatypeIRI) {
super.set(predicateIRI, value, datatypeIRI);
return this;
}

@Override
@Deprecated
@SuppressWarnings("unchecked")
public <T> @Nullable T get(String predicateIRI) {
return (T) properties.get(predicateIRI);
}

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

@Override
public Set<String> predicateIRIs() {
return properties.keySet();
public Thing.Builder<? extends Thing> copy() {
return this;
}

@Override
public @Nullable String datatype(String predicateIRI) {
return datatypes.get(predicateIRI);
public final int hashCode() {
return ThingHashCodeEqualsToString.hashCode(this);
}

@Override
public Map<String, String> datatypes() {
return datatypes;
@SuppressWarnings({"EqualsWhichDoesntCheckParameterClass", "EqualsDoesntCheckParameterClass"})
public final boolean equals(Object obj) {
return ThingHashCodeEqualsToString.equals(this, obj);
}

@Override
@Deprecated
public Builder<? extends Thing> copy() {
return this;
public final String toString() {
return ThingHashCodeEqualsToString.toString(this);
}

@Override
@SuppressWarnings("unchecked") // TODO How to remove (B) type cast?!
public B build() {
var immutableBuilder = ImmutableThing.builderWithExpectedSize(properties.size());
immutableBuilder.iri(iri);
for (Map.Entry<String, Object> entry : properties.entrySet()) {
var predicateIRI = entry.getKey();
immutableBuilder.set(predicateIRI, entry.getValue(), datatype(predicateIRI));
}
IImmutableThing immutableThing = immutableBuilder.build();
return (B) immutableThing;
deepBuildInto(immutableBuilder);
return (B) immutableBuilder.build();
}
}
5 changes: 3 additions & 2 deletions java/dev/enola/thing/impl/ThingHashCodeEqualsToString.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ final class ThingHashCodeEqualsToString {
static boolean equals(PredicatesObjects thiz, @Nullable Object obj) {
if (obj == thiz) return true;
if (obj == null) return false;
// NOT: if (getClass() != obj.getClass()) return false;
// NOT: if (getClass() != obj.getClass()) return false;
if (obj instanceof Thing) return false; // TODO is this a good idea? But what's better?
if (!(obj instanceof ImmutablePredicatesObjects other)) return false;
return Objects.equals(thiz.properties(), other.properties)
&& Objects.equals(thiz.datatypes(), other.datatypes);
Expand All @@ -40,7 +41,7 @@ static boolean equals(PredicatesObjects thiz, @Nullable Object obj) {
static boolean equals(Thing thiz, @Nullable Object obj) {
if (obj == thiz) return true;
if (obj == null) return false;
// NOT: if (getClass() != obj.getClass()) 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())
Expand Down

0 comments on commit aa9c6db

Please sign in to comment.