|
| 1 | +/* |
| 2 | + * Licensed to the Apache Software Foundation (ASF) under one or more |
| 3 | + * contributor license agreements. See the NOTICE file distributed with |
| 4 | + * this work for additional information regarding copyright ownership. |
| 5 | + * The ASF licenses this file to You under the Apache License, Version 2.0 |
| 6 | + * (the "License"); you may not use this file except in compliance with |
| 7 | + * the License. You may obtain a copy of the License at |
| 8 | + * |
| 9 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | + * |
| 11 | + * Unless required by applicable law or agreed to in writing, software |
| 12 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | + * See the License for the specific language governing permissions and |
| 15 | + * limitations under the License. |
| 16 | + */ |
| 17 | +package opennlp.tools.wordnet; |
| 18 | + |
| 19 | +import java.util.Collections; |
| 20 | +import java.util.EnumMap; |
| 21 | +import java.util.List; |
| 22 | +import java.util.Map; |
| 23 | + |
| 24 | +import opennlp.tools.commons.ThreadSafe; |
| 25 | + |
| 26 | +/** |
| 27 | + * One synonym set: a single lexicalized concept with its member lemmas, gloss, and typed |
| 28 | + * relations to other synsets. |
| 29 | + * |
| 30 | + * <p>The {@link #id() id} is an opaque, source-qualified string minted by the reader that |
| 31 | + * produced the synset; consumers must not parse it, only pass it back to |
| 32 | + * {@link LexicalKnowledgeBase#synset(String)} and compare it for equality. Relations map each |
| 33 | + * {@link WordNetRelation} present on this synset to the target synset ids in source order.</p> |
| 34 | + * |
| 35 | + * <p>Instances are immutable and thread-safe: the list and map components are defensively |
| 36 | + * copied to immutable views at construction.</p> |
| 37 | + * |
| 38 | + * @param id The opaque, source-qualified synset identifier. Must not be {@code null} or |
| 39 | + * empty. |
| 40 | + * @param pos The part of speech. Must not be {@code null}. |
| 41 | + * @param lemmas The member lemmas in source order, human-readable (multiword lemmas use |
| 42 | + * spaces, not the underscores some formats store). Must not be {@code null} and |
| 43 | + * must not contain {@code null} or empty elements. May be empty for an |
| 44 | + * unlexicalized concept retained as a relation target. |
| 45 | + * @param gloss The definition text, possibly empty when the source has none. Must not be |
| 46 | + * {@code null}. |
| 47 | + * @param relations The typed relations, each mapping to the target synset ids in source order. |
| 48 | + * Must not be {@code null}; keys must not be {@code null}; each value must be |
| 49 | + * a non-empty list of non-{@code null}, non-empty target ids. |
| 50 | + */ |
| 51 | +@ThreadSafe |
| 52 | +public record Synset( |
| 53 | + String id, |
| 54 | + WordNetPOS pos, |
| 55 | + List<String> lemmas, |
| 56 | + String gloss, |
| 57 | + Map<WordNetRelation, List<String>> relations) { |
| 58 | + |
| 59 | + /** |
| 60 | + * Creates a synset. |
| 61 | + * |
| 62 | + * @throws IllegalArgumentException Thrown if any component violates its documented constraint. |
| 63 | + */ |
| 64 | + public Synset { |
| 65 | + if (id == null || id.isEmpty()) { |
| 66 | + throw new IllegalArgumentException("Id must not be null or empty"); |
| 67 | + } |
| 68 | + if (pos == null) { |
| 69 | + throw new IllegalArgumentException("Pos must not be null"); |
| 70 | + } |
| 71 | + if (lemmas == null) { |
| 72 | + throw new IllegalArgumentException("Lemmas must not be null for synset " + id); |
| 73 | + } |
| 74 | + for (final String lemma : lemmas) { |
| 75 | + if (lemma == null || lemma.isEmpty()) { |
| 76 | + throw new IllegalArgumentException( |
| 77 | + "Lemmas must not contain a null or empty element for synset " + id); |
| 78 | + } |
| 79 | + } |
| 80 | + if (gloss == null) { |
| 81 | + throw new IllegalArgumentException("Gloss must not be null for synset " + id); |
| 82 | + } |
| 83 | + if (relations == null) { |
| 84 | + throw new IllegalArgumentException("Relations must not be null for synset " + id); |
| 85 | + } |
| 86 | + final Map<WordNetRelation, List<String>> copiedRelations = |
| 87 | + new EnumMap<>(WordNetRelation.class); |
| 88 | + for (final Map.Entry<WordNetRelation, List<String>> relation : relations.entrySet()) { |
| 89 | + if (relation.getKey() == null) { |
| 90 | + throw new IllegalArgumentException("Relations must not contain a null key for synset " + id); |
| 91 | + } |
| 92 | + final List<String> targets = relation.getValue(); |
| 93 | + if (targets == null || targets.isEmpty()) { |
| 94 | + throw new IllegalArgumentException("Relation " + relation.getKey() |
| 95 | + + " must map to a non-empty target list for synset " + id); |
| 96 | + } |
| 97 | + for (final String target : targets) { |
| 98 | + if (target == null || target.isEmpty()) { |
| 99 | + throw new IllegalArgumentException("Relation " + relation.getKey() |
| 100 | + + " must not contain a null or empty target id for synset " + id); |
| 101 | + } |
| 102 | + } |
| 103 | + copiedRelations.put(relation.getKey(), List.copyOf(targets)); |
| 104 | + } |
| 105 | + lemmas = List.copyOf(lemmas); |
| 106 | + relations = Collections.unmodifiableMap(copiedRelations); |
| 107 | + } |
| 108 | + |
| 109 | + /** |
| 110 | + * Finds the target synset ids of one relation type. |
| 111 | + * |
| 112 | + * @param relation The relation type. Must not be {@code null}. |
| 113 | + * @return The target synset ids in source order, never {@code null}; empty when this synset |
| 114 | + * has no relation of that type. |
| 115 | + * @throws IllegalArgumentException Thrown if {@code relation} is {@code null}. |
| 116 | + */ |
| 117 | + public List<String> related(WordNetRelation relation) { |
| 118 | + if (relation == null) { |
| 119 | + throw new IllegalArgumentException("Relation must not be null"); |
| 120 | + } |
| 121 | + final List<String> targets = relations.get(relation); |
| 122 | + return targets == null ? List.of() : targets; |
| 123 | + } |
| 124 | +} |
0 commit comments