001/* 002 * SPDX-License-Identifier: Apache-2.0 003 * 004 * Copyright 2024-2026 The Enola <https://enola.dev> Authors 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package dev.enola.thing.impl; 019 020import com.google.errorprone.annotations.ImmutableTypeParameter; 021 022import dev.enola.thing.HasPredicateIRI; 023import dev.enola.thing.Thing; 024import dev.enola.thing.ThingOrBuilder; 025import dev.enola.thing.java.HasType; 026import dev.enola.thing.java.RdfAnnotations; 027import dev.enola.thing.java.TBF; 028 029import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 030 031import org.jspecify.annotations.Nullable; 032 033/** 034 * Implementation of both {@link Thing} and its {@link Thing.Builder} which is simple and mutable. 035 * 036 * <p>When {@link #build()} then it returns an {@link IImmutableThing} copy of this (NOT itself). 037 * 038 * <p>This implementation is pretty inefficient, for both its runtime performance and memory 039 * consumption, and should only be used "shortly lived"; prefer (building this into a) {@link 040 * IImmutableThing} implementations, such as (typically) the {@link ImmutableThing} or its generated 041 * subclasses, for any objects that will be "kept around". 042 * 043 * <p>This implementation is not thread safe, obviously. 044 */ 045// TODO Make MutableThing package private, and let users create them only via the #FACTORY TBF 046@SuppressFBWarnings("EQ_DOESNT_OVERRIDE_EQUALS") 047// skipcq: JAVA-W0100 048public class MutableThing<B extends IImmutableThing> extends MutablePredicatesObjects<B> 049 implements ThingOrBuilder<B> { 050 051 public static final TBF FACTORY = 052 new TBF() { 053 @Override 054 public boolean handles(String typeIRI) { 055 return true; 056 } 057 058 @Override 059 @SuppressWarnings("Immutable") // TODO Error Prone bug?! 060 public Thing.Builder<Thing> create(String typeIRI) { 061 return new MutableThing().add(HasType.IRI, typeIRI); 062 } 063 064 @Override 065 @SuppressWarnings({"unchecked", "rawtypes"}) 066 public <T extends Thing, TB extends Thing.Builder<T>> TB create( 067 Class<TB> builderInterface, Class<T> thingInterface) { 068 var builder = (TB) new MutableThing(); 069 RdfAnnotations.addType(thingInterface, builder); 070 return builder; 071 } 072 073 @Override 074 @SuppressWarnings({"unchecked", "rawtypes"}) 075 public <T extends Thing, TB extends Thing.Builder<T>> TB create( 076 Class<TB> builderInterface, Class<T> thingInterface, int expectedSize) { 077 var builder = (TB) new MutableThing(expectedSize); 078 RdfAnnotations.addType(thingInterface, builder); 079 return builder; 080 } 081 }; 082 083 private @Nullable String iri; 084 085 public MutableThing() { 086 super(); 087 } 088 089 public MutableThing(int expectedSize) { 090 super(expectedSize); 091 } 092 093 @Override 094 public Thing.Builder<B> iri(String iri) { 095 this.iri = iri; 096 return this; 097 } 098 099 @Override 100 public String iri() { 101 if (iri == null) throw new IllegalStateException(); 102 return iri; 103 } 104 105 @Override 106 public <@ImmutableTypeParameter T> Thing.Builder<B> set(String predicateIRI, T value) { 107 super.set(predicateIRI, value); 108 return this; 109 } 110 111 @Override 112 public <@ImmutableTypeParameter T> Thing.Builder<B> set( 113 String predicateIRI, T value, @Nullable String datatypeIRI) { 114 super.set(predicateIRI, value, datatypeIRI); 115 return this; 116 } 117 118 @Override 119 public <@ImmutableTypeParameter T> Thing.Builder<B> add(String predicateIRI, T value) { 120 super.add(predicateIRI, value); 121 return this; 122 } 123 124 @Override 125 public <@ImmutableTypeParameter T> Thing.Builder<B> addAll( 126 String predicateIRI, Iterable<T> values) { 127 super.addAll(predicateIRI, values); 128 return this; 129 } 130 131 @Override 132 public <@ImmutableTypeParameter T> Thing.Builder<B> add( 133 String predicateIRI, T value, @Nullable String datatypeIRI) { 134 super.add(predicateIRI, value, datatypeIRI); 135 return this; 136 } 137 138 @Override 139 public <@ImmutableTypeParameter T> Thing.Builder<B> addAll( 140 String predicateIRI, Iterable<T> values, @Nullable String datatypeIRI) { 141 super.addAll(predicateIRI, values, datatypeIRI); 142 return this; 143 } 144 145 @Override 146 public <@ImmutableTypeParameter T> Thing.Builder<B> addOrdered(String predicateIRI, T value) { 147 super.addOrdered(predicateIRI, value); 148 return this; 149 } 150 151 @Override 152 public <@ImmutableTypeParameter T> Thing.Builder<B> addOrdered( 153 String predicateIRI, T value, @Nullable String datatypeIRI) { 154 super.addOrdered(predicateIRI, value, datatypeIRI); 155 return this; 156 } 157 158 @Override 159 public <@ImmutableTypeParameter T> Thing.Builder<B> add(HasPredicateIRI predicate, T value) { 160 super.add(predicate, value); 161 return this; 162 } 163 164 @Override 165 public <@ImmutableTypeParameter T> Thing.Builder<B> add( 166 HasPredicateIRI predicate, T value, @Nullable String datatypeIRI) { 167 super.add(predicate, value, datatypeIRI); 168 return this; 169 } 170 171 @Override 172 public <@ImmutableTypeParameter T> Thing.Builder<B> addAll( 173 HasPredicateIRI predicate, Iterable<T> value) { 174 super.addAll(predicate, value); 175 return this; 176 } 177 178 @Override 179 public <@ImmutableTypeParameter T> Thing.Builder<B> addAll( 180 HasPredicateIRI predicate, Iterable<T> value, @Nullable String datatypeIRI) { 181 super.addAll(predicate, value, datatypeIRI); 182 return this; 183 } 184 185 @Override 186 public <@ImmutableTypeParameter T> Thing.Builder<B> addOrdered( 187 HasPredicateIRI predicate, T value) { 188 super.addOrdered(predicate, value); 189 return this; 190 } 191 192 @Override 193 public <@ImmutableTypeParameter T> Thing.Builder<B> addOrdered( 194 HasPredicateIRI predicate, T value, @Nullable String datatypeIRI) { 195 super.addOrdered(predicate, value, datatypeIRI); 196 return this; 197 } 198 199 @Override 200 public Thing.Builder<? extends Thing> copy() { 201 return this; 202 } 203 204 @Override 205 public final int hashCode() { 206 return ThingHashCodeEqualsToString.hashCode(this); 207 } 208 209 @Override 210 @SuppressWarnings({"EqualsWhichDoesntCheckParameterClass", "EqualsDoesntCheckParameterClass"}) 211 public final boolean equals(Object obj) { 212 return ThingHashCodeEqualsToString.equals(this, obj); 213 } 214 215 @Override 216 public final String toString() { 217 return ThingHashCodeEqualsToString.toString(this, properties, datatypes); 218 } 219 220 @Override 221 @SuppressWarnings("unchecked") 222 public B build() { 223 if (iri == null) throw new IllegalStateException(PackageLocalConstants.NEEDS_IRI_MESSAGE); 224 225 var pair = ImmutableObjects.build(properties, datatypes); 226 return (B) new ImmutableThing(iri, pair.properties(), pair.datatypes()); 227 } 228}