diff --git a/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/Bar.java b/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/Bar.java index b9d0b28..2d8f4d5 100644 --- a/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/Bar.java +++ b/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/Bar.java @@ -1,19 +1,74 @@ package org.incenp.linkml.core.samples.refinhslot; -/** - * An example of a class that is used in a “refined” slot. - *

- * This class is used in the {@link Foo} class. Some of the classes that are - * derived from Foo uses derived classes instead. - */ +import java.net.URI; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.incenp.linkml.core.annotations.Converter; +import org.incenp.linkml.core.annotations.ExtensionHolder; +import org.incenp.linkml.core.annotations.Identifier; +import org.incenp.linkml.core.annotations.Inlined; +import org.incenp.linkml.core.annotations.LinkURI; +import org.incenp.linkml.core.annotations.Required; +import org.incenp.linkml.core.annotations.SlotName; +import org.incenp.linkml.core.annotations.TypeDesignator; +import org.incenp.linkml.core.CurieConverter; + +@LinkURI("https://w3id.org/linkml/tests/refined_derived_slots/Bar") public class Bar { + + @LinkURI("https://w3id.org/linkml/tests/refined_derived_slots/name") private String name; + public void setName(String name) { + this.name = name; + } + public String getName() { - return name; + return this.name; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + Object o; + sb.append("Bar("); + if ( (o = this.getName()) != null ) { + sb.append("name="); + sb.append(o); + sb.append(","); + } + sb.append(")"); + return sb.toString(); + } + + @Override + public boolean equals(final Object o) { + if ( o == this ) return true; + if ( !(o instanceof Bar) ) return false; + final Bar other = (Bar) o; + if ( !other.canEqual((Object) this)) return false; + final Object this$name = this.getName(); + final Object other$name = other.getName(); + if ( this$name == null ? other$name != null : !this$name.equals(other$name)) return false; + return true; + } + + protected boolean canEqual(final Object other) { + return other instanceof Bar; } - public void setName(String value) { - name = value; + @Override + public int hashCode() { + final int PRIME = 59; + int result = 1; + final Object $name = this.getName(); + result = result * PRIME + ($name == null ? 43 : $name.hashCode()); + return result; } -} +} \ No newline at end of file diff --git a/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/FirstDerivedBar.java b/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/FirstDerivedBar.java index efe9acb..ada1f58 100644 --- a/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/FirstDerivedBar.java +++ b/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/FirstDerivedBar.java @@ -1,20 +1,81 @@ package org.incenp.linkml.core.samples.refinhslot; -/** - * First derived class from Bar. - *

- * This class is used, instead of its parent Bar in - * {@link FirstDerivedFoo}. - */ +import java.net.URI; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.incenp.linkml.core.annotations.Converter; +import org.incenp.linkml.core.annotations.ExtensionHolder; +import org.incenp.linkml.core.annotations.Identifier; +import org.incenp.linkml.core.annotations.Inlined; +import org.incenp.linkml.core.annotations.LinkURI; +import org.incenp.linkml.core.annotations.Required; +import org.incenp.linkml.core.annotations.SlotName; +import org.incenp.linkml.core.annotations.TypeDesignator; +import org.incenp.linkml.core.CurieConverter; + +@LinkURI("https://w3id.org/linkml/tests/refined_derived_slots/FirstDerivedBar") public class FirstDerivedBar extends Bar { - private int length; + @LinkURI("https://w3id.org/linkml/tests/refined_derived_slots/length") + private Integer length; + + public void setLength(Integer length) { + this.length = length; + } + + public Integer getLength() { + return this.length; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + Object o; + sb.append("FirstDerivedBar("); + if ( (o = this.getLength()) != null ) { + sb.append("length="); + sb.append(o); + sb.append(","); + } + if ( (o = this.getName()) != null ) { + sb.append("name="); + sb.append(o); + sb.append(","); + } + sb.append(")"); + return sb.toString(); + } + + @Override + public boolean equals(final Object o) { + if ( o == this ) return true; + if ( !(o instanceof FirstDerivedBar) ) return false; + final FirstDerivedBar other = (FirstDerivedBar) o; + if ( !other.canEqual((Object) this)) return false; + if ( !super.equals(o) ) return false; + + final Object this$length = this.getLength(); + final Object other$length = other.getLength(); + if ( this$length == null ? other$length != null : !this$length.equals(other$length)) return false; + return true; + } - public int getLength() { - return length; + protected boolean canEqual(final Object other) { + return other instanceof FirstDerivedBar; } - public void setLength(int value) { - length = value; + @Override + public int hashCode() { + final int PRIME = 59; + int result = super.hashCode(); + final Object $length = this.getLength(); + result = result * PRIME + ($length == null ? 43 : $length.hashCode()); + return result; } -} +} \ No newline at end of file diff --git a/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/FirstDerivedFoo.java b/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/FirstDerivedFoo.java index 8f1c450..8f403cf 100644 --- a/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/FirstDerivedFoo.java +++ b/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/FirstDerivedFoo.java @@ -1,33 +1,36 @@ package org.incenp.linkml.core.samples.refinhslot; +import java.net.URI; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; -/** - * An example of a class that refines the range of its slots to make them accept - * only a more specialised subclass. - */ +import org.incenp.linkml.core.annotations.Converter; +import org.incenp.linkml.core.annotations.ExtensionHolder; +import org.incenp.linkml.core.annotations.Identifier; +import org.incenp.linkml.core.annotations.Inlined; +import org.incenp.linkml.core.annotations.LinkURI; +import org.incenp.linkml.core.annotations.Required; +import org.incenp.linkml.core.annotations.SlotName; +import org.incenp.linkml.core.annotations.TypeDesignator; +import org.incenp.linkml.core.CurieConverter; + +@LinkURI("https://w3id.org/linkml/tests/refined_derived_slots/FirstDerivedFoo") public class FirstDerivedFoo extends Foo { - /* - * Overridden read accessor for the `bar` slot. - * - * We override it to ensure that it returns the more specialised subtype. - */ @Override public FirstDerivedBar getBar() { - // This cast is perfectly safe because the write accessor below guarantees that - // only a FirstDerivedBar object can be assigned to the slot. return (FirstDerivedBar) super.getBar(); } - /* - * Overridden write accessor for the `bar` slot. - * - * We override it to add a runtime check to enforce the more specialised type - * constraint. We cannot prevent client code from trying to assign an object of - * the wrong type, but if that happens we can at least immediately throw an - * exception. - */ + public void setBar(FirstDerivedBar value) { + super.setBar(value); + } + @Override public void setBar(Bar value) { if ( !(value instanceof FirstDerivedBar) ) { @@ -36,54 +39,17 @@ public void setBar(Bar value) { super.setBar(value); } - /* - * Overloaded write accessor for the `bar` slot. - * - * This accessor is not strictly necessary, but it makes it clearer that in this - * class, the value of the `bar` slot should be a `FirstDerivedBar`. It also - * allows to bypass the dynamic check in the normal accessor above, if the - * compiler already knows that the assigned value is a FirstDerivedBar. - */ - public void setBar(FirstDerivedBar value) { - super.setBar(value); - } - - /* - * Overridden “Standard” read accessor. - * - * We override it to ensure it returns the more specialised subtype. - * - * Because the slot could be (and instead is, in this example) refined further - * in subclasses, we must still return a generic wildcard, so this accessor has - * the same limitation as the one it overrides in the `Foo` class: modifying the - * returned list requires an explicit cast into a non-wildcard form. - */ @Override @SuppressWarnings("unchecked") public List getBars() { - // This cast should be safe IFF nobody explicitly modify the value returned by - // this accessor after casting it into a `List`. return (List) super.getBars(); } - /* - * Overridden read accessor with optional creation of the list. - * - * We must override this accessor to ensure that the created list (if the list - * needs to be created) is using the more specialised type. - */ @Override public List getBars(boolean create) { - // We can delegate the logic to the parent return super.getBars(FirstDerivedBar.class, create); } - /* - * Overridden parameterised read accessor. - * - * We must override this accessor to add a runtime check that the given type - * parameter is compatible with the more specialised type. - */ @Override public List getBars(Class t) { if ( !FirstDerivedBar.class.isAssignableFrom(t) ) { @@ -92,12 +58,6 @@ public List getBars(Class t) { return super.getBars(t); } - /* - * Overridden parameterised read accessor with optional creation of the list. - * - * Same as above: we must override this accessor to add a runtime check on the - * type parameter. - */ @Override public List getBars(Class t, boolean create) { if ( !FirstDerivedBar.class.isAssignableFrom(t) ) { @@ -106,20 +66,56 @@ public List getBars(Class t, boolean create) { return super.getBars(t, create); } - /* - * Overridden “standard” write accessor. - * - * We must override this accessor to include a runtime check. The check must be - * performed on all list items. - */ @Override public void setBars(List value) { - for ( Bar b : value ) { - if ( !(b instanceof FirstDerivedBar) ) { - throw new IllegalArgumentException("Invalid bars value"); + if ( value != null ) { + for ( Bar item : value ) { + if ( !(item instanceof FirstDerivedBar) ) { + throw new IllegalArgumentException("Invalid bars value"); + } } } super.setBars(value); } -} + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + Object o; + sb.append("FirstDerivedFoo("); + if ( (o = this.getBar()) != null ) { + sb.append("bar="); + sb.append(o); + sb.append(","); + } + if ( (o = this.getBars()) != null ) { + sb.append("bars="); + sb.append(o); + sb.append(","); + } + sb.append(")"); + return sb.toString(); + } + + @Override + public boolean equals(final Object o) { + if ( o == this ) return true; + if ( !(o instanceof FirstDerivedFoo) ) return false; + final FirstDerivedFoo other = (FirstDerivedFoo) o; + if ( !other.canEqual((Object) this)) return false; + if ( !super.equals(o) ) return false; + + return true; + } + + protected boolean canEqual(final Object other) { + return other instanceof FirstDerivedFoo; + } + + @Override + public int hashCode() { + final int PRIME = 59; + int result = super.hashCode(); + return result; + } +} \ No newline at end of file diff --git a/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/Foo.java b/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/Foo.java index 7082bf6..8fc9d46 100644 --- a/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/Foo.java +++ b/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/Foo.java @@ -1,100 +1,115 @@ package org.incenp.linkml.core.samples.refinhslot; +import java.net.URI; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZonedDateTime; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; -/** - * An example of a class whose slots are “refined” in derived classes. - */ +import org.incenp.linkml.core.annotations.Converter; +import org.incenp.linkml.core.annotations.ExtensionHolder; +import org.incenp.linkml.core.annotations.Identifier; +import org.incenp.linkml.core.annotations.Inlined; +import org.incenp.linkml.core.annotations.LinkURI; +import org.incenp.linkml.core.annotations.Required; +import org.incenp.linkml.core.annotations.SlotName; +import org.incenp.linkml.core.annotations.TypeDesignator; +import org.incenp.linkml.core.CurieConverter; + +@LinkURI("https://w3id.org/linkml/tests/refined_derived_slots/Foo") public class Foo { + @LinkURI("https://w3id.org/linkml/tests/refined_derived_slots/bar") private Bar bar; - // We use a wildcard generic to allow derived classes to “refine” the parameter - // type + @LinkURI("https://w3id.org/linkml/tests/refined_derived_slots/bars") private List bars; - /* - * Accessors for the `bar` slot. - * - * Nothing out of the ordinary here. - */ + public void setBar(Bar bar) { + this.bar = bar; + } + public Bar getBar() { - return bar; + return this.bar; } - public void setBar(Bar value) { - bar = value; + public void setBars(List bars) { + this.bars = bars; } - /* - * Accessors for the multi-valued `bars` slot. - */ - - /* - * “Standard” read accessor. Its return type is parameterized with a wildcard - * generic to allow derived classes to refine the parameter. - * - * Modifying the returned list is only possible by explicitly casting it to a - * non-wildcard form, as in: - * - * ((List) foo.getBars()).add(new Bar()); - * - * Without the cast, the following would be a compile-time error: - * - * foo.getBars().add(new Bar()); - */ public List getBars() { - return bars; + return this.bars; } - /* - * LinkML-Java “Standard” read accessor with optional creation of the list. - * - * This is a convenience accessor, intended to allow client code to dispense - * with a null-ness check. - * - * As for the argument-less read accessor, the return type is a wildcard, so - * modifying the returned list requires an explicit cast. - */ - public List getBars(boolean create) { - if ( bars == null && create ) { - bars = new ArrayList(); + public List getBars(boolean set) { + if ( this.bars == null && set ) { + this.bars = new ArrayList(); } - return bars; + return this.bars; } - /* - * Parameterised read accessor. - * - * This is another convenience accessor. This one is intended to allow client - * code to dispense with an explicit cast to modify the list: - * - * foo.getBars(Bar.class).add(new Bar()); - */ @SuppressWarnings("unchecked") public List getBars(Class t) { - return (List) bars; + return (List) this.bars; } - /* - * Parameterised read accessor with optional creation of the list. - * - * This is another convenience accessor, combining the effects of the two - * accessors above. - */ @SuppressWarnings("unchecked") public List getBars(Class t, boolean create) { - if ( bars == null && create ) { - bars = new ArrayList(); + if ( this.bars == null && create ) { + this.bars = new ArrayList(); + } + return (List) this.bars; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + Object o; + sb.append("Foo("); + if ( (o = this.getBar()) != null ) { + sb.append("bar="); + sb.append(o); + sb.append(","); } - return (List) bars; + if ( (o = this.getBars()) != null ) { + sb.append("bars="); + sb.append(o); + sb.append(","); + } + sb.append(")"); + return sb.toString(); + } + + @Override + public boolean equals(final Object o) { + if ( o == this ) return true; + if ( !(o instanceof Foo) ) return false; + final Foo other = (Foo) o; + if ( !other.canEqual((Object) this)) return false; + final Object this$bar = this.getBar(); + final Object other$bar = other.getBar(); + if ( this$bar == null ? other$bar != null : !this$bar.equals(other$bar)) return false; + final Object this$bars = this.getBars(); + final Object other$bars = other.getBars(); + if ( this$bars == null ? other$bars != null : !this$bars.equals(other$bars)) return false; + return true; + } + + protected boolean canEqual(final Object other) { + return other instanceof Foo; } - /* - * “Standard” write accessor. - */ - public void setBars(List value) { - bars = value; + @Override + public int hashCode() { + final int PRIME = 59; + int result = 1; + final Object $bar = this.getBar(); + result = result * PRIME + ($bar == null ? 43 : $bar.hashCode()); + final Object $bars = this.getBars(); + result = result * PRIME + ($bars == null ? 43 : $bars.hashCode()); + return result; } -} +} \ No newline at end of file diff --git a/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/SecondDerivedBar.java b/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/SecondDerivedBar.java index ec6a52c..bf0cc4c 100644 --- a/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/SecondDerivedBar.java +++ b/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/SecondDerivedBar.java @@ -1,11 +1,86 @@ package org.incenp.linkml.core.samples.refinhslot; -/** - * Second derived class from Bar. - *

- * This class is used, instead of its parent FirstDerivedBar, in - * {@link ThirdDerivedFoo}. - */ +import java.net.URI; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.incenp.linkml.core.annotations.Converter; +import org.incenp.linkml.core.annotations.ExtensionHolder; +import org.incenp.linkml.core.annotations.Identifier; +import org.incenp.linkml.core.annotations.Inlined; +import org.incenp.linkml.core.annotations.LinkURI; +import org.incenp.linkml.core.annotations.Required; +import org.incenp.linkml.core.annotations.SlotName; +import org.incenp.linkml.core.annotations.TypeDesignator; +import org.incenp.linkml.core.CurieConverter; + +@LinkURI("https://w3id.org/linkml/tests/refined_derived_slots/SecondDerivedBar") public class SecondDerivedBar extends FirstDerivedBar { -} + @LinkURI("https://w3id.org/linkml/tests/refined_derived_slots/width") + private Integer width; + + public void setWidth(Integer width) { + this.width = width; + } + + public Integer getWidth() { + return this.width; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + Object o; + sb.append("SecondDerivedBar("); + if ( (o = this.getWidth()) != null ) { + sb.append("width="); + sb.append(o); + sb.append(","); + } + if ( (o = this.getLength()) != null ) { + sb.append("length="); + sb.append(o); + sb.append(","); + } + if ( (o = this.getName()) != null ) { + sb.append("name="); + sb.append(o); + sb.append(","); + } + sb.append(")"); + return sb.toString(); + } + + @Override + public boolean equals(final Object o) { + if ( o == this ) return true; + if ( !(o instanceof SecondDerivedBar) ) return false; + final SecondDerivedBar other = (SecondDerivedBar) o; + if ( !other.canEqual((Object) this)) return false; + if ( !super.equals(o) ) return false; + + final Object this$width = this.getWidth(); + final Object other$width = other.getWidth(); + if ( this$width == null ? other$width != null : !this$width.equals(other$width)) return false; + return true; + } + + protected boolean canEqual(final Object other) { + return other instanceof SecondDerivedBar; + } + + @Override + public int hashCode() { + final int PRIME = 59; + int result = super.hashCode(); + final Object $width = this.getWidth(); + result = result * PRIME + ($width == null ? 43 : $width.hashCode()); + return result; + } +} \ No newline at end of file diff --git a/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/SecondDerivedFoo.java b/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/SecondDerivedFoo.java index 6ab2a54..67266b0 100644 --- a/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/SecondDerivedFoo.java +++ b/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/SecondDerivedFoo.java @@ -1,13 +1,65 @@ package org.incenp.linkml.core.samples.refinhslot; -/** - * An example of a class that inherits from a class that refines its slots, but - * that does no do any refinement itself. - */ +import java.net.URI; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.incenp.linkml.core.annotations.Converter; +import org.incenp.linkml.core.annotations.ExtensionHolder; +import org.incenp.linkml.core.annotations.Identifier; +import org.incenp.linkml.core.annotations.Inlined; +import org.incenp.linkml.core.annotations.LinkURI; +import org.incenp.linkml.core.annotations.Required; +import org.incenp.linkml.core.annotations.SlotName; +import org.incenp.linkml.core.annotations.TypeDesignator; +import org.incenp.linkml.core.CurieConverter; + +@LinkURI("https://w3id.org/linkml/tests/refined_derived_slots/SecondDerivedFoo") public class SecondDerivedFoo extends FirstDerivedFoo { - /* - * In this class, the `bar` and `bars` slot are of the same type as in the - * parental `FirstDerivedFoo` class, so no overriding of accessors is necessary. - */ -} + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + Object o; + sb.append("SecondDerivedFoo("); + if ( (o = this.getBar()) != null ) { + sb.append("bar="); + sb.append(o); + sb.append(","); + } + if ( (o = this.getBars()) != null ) { + sb.append("bars="); + sb.append(o); + sb.append(","); + } + sb.append(")"); + return sb.toString(); + } + + @Override + public boolean equals(final Object o) { + if ( o == this ) return true; + if ( !(o instanceof SecondDerivedFoo) ) return false; + final SecondDerivedFoo other = (SecondDerivedFoo) o; + if ( !other.canEqual((Object) this)) return false; + if ( !super.equals(o) ) return false; + + return true; + } + + protected boolean canEqual(final Object other) { + return other instanceof SecondDerivedFoo; + } + + @Override + public int hashCode() { + final int PRIME = 59; + int result = super.hashCode(); + return result; + } +} \ No newline at end of file diff --git a/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/ThirdDerivedFoo.java b/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/ThirdDerivedFoo.java index e06104a..89c3f52 100644 --- a/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/ThirdDerivedFoo.java +++ b/core/src/test/java/org/incenp/linkml/core/samples/refinhslot/ThirdDerivedFoo.java @@ -1,48 +1,36 @@ package org.incenp.linkml.core.samples.refinhslot; +import java.net.URI; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; -/** - * An example of a class that refines the range of its slots, that it inherited - * from a class that already refined them. - * - * Importantly, this class has no derived class, so we know its slots cannot be - * further refined by another class. - */ +import org.incenp.linkml.core.annotations.Converter; +import org.incenp.linkml.core.annotations.ExtensionHolder; +import org.incenp.linkml.core.annotations.Identifier; +import org.incenp.linkml.core.annotations.Inlined; +import org.incenp.linkml.core.annotations.LinkURI; +import org.incenp.linkml.core.annotations.Required; +import org.incenp.linkml.core.annotations.SlotName; +import org.incenp.linkml.core.annotations.TypeDesignator; +import org.incenp.linkml.core.CurieConverter; + +@LinkURI("https://w3id.org/linkml/tests/refined_derived_slots/ThirdDerivedFoo") public class ThirdDerivedFoo extends SecondDerivedFoo { - /* - * Overridden read accessor for the `bar` slot. - * - * We override it to ensure that it returns the more specialised subtype. - */ @Override public SecondDerivedBar getBar() { return (SecondDerivedBar) super.getBar(); } - /* - * Overridden write accessor for the `bar` slot. - * - * We override it to add a runtime check to enforce the more specialised type - * constraint. We cannot prevent client code from trying to assign an object of - * the wrong type, but if that happens we can at least immediately throw an - * exception. - */ - @Override - public void setBar(Bar value) { - if ( !(value instanceof SecondDerivedBar) ) { - throw new IllegalArgumentException("Invalid bar value"); - } + public void setBar(SecondDerivedBar value) { super.setBar(value); } - /* - * Second overridden write accessor for the `bar` slot. - * - * Since `FirstDerivedFoo` defined this accessor, we must override it as well, - * otherwise it would allow client code to assign a FirstDerivedBar to the slot. - */ @Override public void setBar(FirstDerivedBar value) { if ( !(value instanceof SecondDerivedBar) ) { @@ -51,52 +39,25 @@ public void setBar(FirstDerivedBar value) { super.setBar(value); } - /* - * Overloaded write accessor for the `bar` slot. - * - * This accessor is not strictly necessary, but it makes it clearer that in this - * class, the value of the `bar` slot should be a `SecondDerivedBar`. It also - * allows to bypass the dynamic check in the normal accessor above, if the - * compiler already knows that the assigned value is a FirstDerivedBar. - */ - public void setBar(SecondDerivedBar value) { + @Override + public void setBar(Bar value) { + if ( !(value instanceof SecondDerivedBar) ) { + throw new IllegalArgumentException("Invalid bar value"); + } super.setBar(value); } - /* - * Overridden “standard” read accessor. - * - * We override it to ensure it returns the more specialised subtype. - * - * Here, since we know the slot cannot be further refined (no subclass), we can - * dispense with a wildcard generic. - */ @Override @SuppressWarnings("unchecked") public List getBars() { return (List) super.getBars(); } - /* - * Overriden read accessor with optional creation of the list. - * - * We must override this accessor to ensure that the created list (if the list - * needs to be created) is using the more specialised type. - */ @Override public List getBars(boolean create) { - // We can delegate the logic to the parent return super.getBars(SecondDerivedBar.class, create); } - /* - * Overidden parameterised read accessor. - * - * In this class, we don’t need this accessor to get a modifiable list (we can - * use `getBars()` directly), but we must still override the accessor we inherit - * from the parent, otherwise this would allow client code to get a - * `List`-typed value. - */ @Override public List getBars(Class t) { if ( !SecondDerivedBar.class.isAssignableFrom(t) ) { @@ -105,12 +66,6 @@ public List getBars(Class t) { return super.getBars(t); } - /* - * Overridden parameterised read accessor with optional creation of the list. - * - * Same as above: we must override this accessor to add a runtime check on the - * type parameter. - */ @Override public List getBars(Class t, boolean create) { if ( !SecondDerivedBar.class.isAssignableFrom(t) ) { @@ -119,21 +74,56 @@ public List getBars(Class t, boolean create) { return super.getBars(t, create); } - /* - * Overridden “standard” write accessor. - * - * We must override this accessor to include a runtime check. The check must be - * performed on all list items. - */ @Override public void setBars(List value) { - for ( Bar b : value ) { - if ( !(b instanceof SecondDerivedBar) ) { - throw new IllegalArgumentException("Invalid bar value"); + if ( value != null ) { + for ( Bar item : value ) { + if ( !(item instanceof SecondDerivedBar) ) { + throw new IllegalArgumentException("Invalid bars value"); + } } } - // FIXME: the parent method will in turn perform a (no longer needed) runtime - // check... super.setBars(value); } -} + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + Object o; + sb.append("ThirdDerivedFoo("); + if ( (o = this.getBar()) != null ) { + sb.append("bar="); + sb.append(o); + sb.append(","); + } + if ( (o = this.getBars()) != null ) { + sb.append("bars="); + sb.append(o); + sb.append(","); + } + sb.append(")"); + return sb.toString(); + } + + @Override + public boolean equals(final Object o) { + if ( o == this ) return true; + if ( !(o instanceof ThirdDerivedFoo) ) return false; + final ThirdDerivedFoo other = (ThirdDerivedFoo) o; + if ( !other.canEqual((Object) this)) return false; + if ( !super.equals(o) ) return false; + + return true; + } + + protected boolean canEqual(final Object other) { + return other instanceof ThirdDerivedFoo; + } + + @Override + public int hashCode() { + final int PRIME = 59; + int result = super.hashCode(); + return result; + } +} \ No newline at end of file diff --git a/core/src/test/linkml/refined-inherited-slots.yaml b/core/src/test/linkml/refined-inherited-slots.yaml new file mode 100644 index 0000000..7a28aa1 --- /dev/null +++ b/core/src/test/linkml/refined-inherited-slots.yaml @@ -0,0 +1,60 @@ +id: https://w3id.org/linkml/tests/refined_derived_slots +name: refined_derived_slots +title: Test case for refined derived slots +description: |- + This schema is intended to illustrate and test the case where a + derived class refines (through `slot_usage`) an inherited slot in such + a way that the inherited-and-refined slot has a more specialised range + than the original slot. + +prefixes: + linkml: https://w3id.org/linkml/ +imports: + - linkml:types +default_range: string + +slots: + bar: + range: Bar + bars: + range: Bar + multivalued: true + +classes: + Foo: + attributes: + bar: + range: Bar + bars: + range: Bar + multivalued: true + FirstDerivedFoo: + is_a: Foo + slot_usage: + bar: + range: FirstDerivedBar + bars: + range: FirstDerivedBar + SecondDerivedFoo: + is_a: FirstDerivedFoo + ThirdDerivedFoo: + is_a: SecondDerivedFoo + slot_usage: + bar: + range: SecondDerivedBar + bars: + range: SecondDerivedBar + + Bar: + attributes: + name: + FirstDerivedBar: + is_a: Bar + attributes: + length: + range: integer + SecondDerivedBar: + is_a: FirstDerivedBar + attributes: + width: + range: integer diff --git a/ext/src/main/java/org/incenp/linkml/schema/model/ClassDefinition.java b/ext/src/main/java/org/incenp/linkml/schema/model/ClassDefinition.java index 3f21432..fe521b8 100644 --- a/ext/src/main/java/org/incenp/linkml/schema/model/ClassDefinition.java +++ b/ext/src/main/java/org/incenp/linkml/schema/model/ClassDefinition.java @@ -388,6 +388,101 @@ public List getSlotConditions(boolean set) { return this.slotConditions; } + @Override + public ClassDefinition getIsA() { + return (ClassDefinition) super.getIsA(); + } + + public void setIsA(ClassDefinition value) { + super.setIsA(value); + } + + @Override + public void setIsA(Definition value) { + if ( !(value instanceof ClassDefinition) ) { + throw new IllegalArgumentException("Invalid isA value"); + } + super.setIsA(value); + } + + @Override + @SuppressWarnings("unchecked") + public List getMixins() { + return (List) super.getMixins(); + } + + @Override + public List getMixins(boolean create) { + return super.getMixins(ClassDefinition.class, create); + } + + @Override + public List getMixins(Class t) { + if ( !ClassDefinition.class.isAssignableFrom(t) ) { + throw new IllegalArgumentException("Invalid type parameter"); + } + return super.getMixins(t); + } + + @Override + public List getMixins(Class t, boolean create) { + if ( !ClassDefinition.class.isAssignableFrom(t) ) { + throw new IllegalArgumentException("Invalid type parameter"); + } + return super.getMixins(t, create); + } + + @Override + public void setMixins(List value) { + if ( value != null ) { + for ( Definition item : value ) { + if ( !(item instanceof ClassDefinition) ) { + throw new IllegalArgumentException("Invalid mixins value"); + } + } + } + super.setMixins(value); + } + + @Override + @SuppressWarnings("unchecked") + public List getApplyTo() { + return (List) super.getApplyTo(); + } + + @Override + public List getApplyTo(boolean create) { + return super.getApplyTo(ClassDefinition.class, create); + } + + @Override + public List getApplyTo(Class t) { + if ( !ClassDefinition.class.isAssignableFrom(t) ) { + throw new IllegalArgumentException("Invalid type parameter"); + } + return super.getApplyTo(t); + } + + @Override + public List getApplyTo(Class t, boolean create) { + if ( !ClassDefinition.class.isAssignableFrom(t) ) { + throw new IllegalArgumentException("Invalid type parameter"); + } + return super.getApplyTo(t, create); + } + + @Override + public void setApplyTo(List value) { + if ( value != null ) { + for ( Definition item : value ) { + if ( !(item instanceof ClassDefinition) ) { + throw new IllegalArgumentException("Invalid applyTo value"); + } + } + } + super.setApplyTo(value); + } + @Override public String toString() { return "ClassDefinition(name=" + this.getName() + ")"; diff --git a/ext/src/main/java/org/incenp/linkml/schema/model/Definition.java b/ext/src/main/java/org/incenp/linkml/schema/model/Definition.java index caeafbd..8f6e86c 100644 --- a/ext/src/main/java/org/incenp/linkml/schema/model/Definition.java +++ b/ext/src/main/java/org/incenp/linkml/schema/model/Definition.java @@ -34,11 +34,11 @@ public abstract class Definition extends Element { private Boolean mixin; @LinkURI("https://w3id.org/linkml/mixins") - private List mixins; + private List mixins; @SlotName("apply_to") @LinkURI("https://w3id.org/linkml/apply_to") - private List applyTo; + private List applyTo; @SlotName("values_from") @Converter(CurieConverter.class) @@ -73,36 +73,62 @@ public Boolean getMixin() { return this.mixin; } - public void setMixins(List mixins) { + public void setMixins(List mixins) { this.mixins = mixins; } - public List getMixins() { + public List getMixins() { return this.mixins; } - public List getMixins(boolean set) { + public List getMixins(boolean set) { if ( this.mixins == null && set ) { - this.mixins = new ArrayList<>(); + this.mixins = new ArrayList(); } return this.mixins; } - public void setApplyTo(List applyTo) { + @SuppressWarnings("unchecked") + public List getMixins(Class t) { + return (List) this.mixins; + } + + @SuppressWarnings("unchecked") + public List getMixins(Class t, boolean create) { + if ( this.mixins == null && create ) { + this.mixins = new ArrayList(); + } + return (List) this.mixins; + } + + public void setApplyTo(List applyTo) { this.applyTo = applyTo; } - public List getApplyTo() { + public List getApplyTo() { return this.applyTo; } - public List getApplyTo(boolean set) { + public List getApplyTo(boolean set) { if ( this.applyTo == null && set ) { - this.applyTo = new ArrayList<>(); + this.applyTo = new ArrayList(); } return this.applyTo; } + @SuppressWarnings("unchecked") + public List getApplyTo(Class t) { + return (List) this.applyTo; + } + + @SuppressWarnings("unchecked") + public List getApplyTo(Class t, boolean create) { + if ( this.applyTo == null && create ) { + this.applyTo = new ArrayList(); + } + return (List) this.applyTo; + } + public void setValuesFrom(List valuesFrom) { this.valuesFrom = valuesFrom; } diff --git a/ext/src/main/java/org/incenp/linkml/schema/model/SlotDefinition.java b/ext/src/main/java/org/incenp/linkml/schema/model/SlotDefinition.java index 78b5520..ad07b4f 100644 --- a/ext/src/main/java/org/incenp/linkml/schema/model/SlotDefinition.java +++ b/ext/src/main/java/org/incenp/linkml/schema/model/SlotDefinition.java @@ -873,6 +873,101 @@ public ArrayExpression getArray() { return this.array; } + @Override + public SlotDefinition getIsA() { + return (SlotDefinition) super.getIsA(); + } + + public void setIsA(SlotDefinition value) { + super.setIsA(value); + } + + @Override + public void setIsA(Definition value) { + if ( !(value instanceof SlotDefinition) ) { + throw new IllegalArgumentException("Invalid isA value"); + } + super.setIsA(value); + } + + @Override + @SuppressWarnings("unchecked") + public List getMixins() { + return (List) super.getMixins(); + } + + @Override + public List getMixins(boolean create) { + return super.getMixins(SlotDefinition.class, create); + } + + @Override + public List getMixins(Class t) { + if ( !SlotDefinition.class.isAssignableFrom(t) ) { + throw new IllegalArgumentException("Invalid type parameter"); + } + return super.getMixins(t); + } + + @Override + public List getMixins(Class t, boolean create) { + if ( !SlotDefinition.class.isAssignableFrom(t) ) { + throw new IllegalArgumentException("Invalid type parameter"); + } + return super.getMixins(t, create); + } + + @Override + public void setMixins(List value) { + if ( value != null ) { + for ( Definition item : value ) { + if ( !(item instanceof SlotDefinition) ) { + throw new IllegalArgumentException("Invalid mixins value"); + } + } + } + super.setMixins(value); + } + + @Override + @SuppressWarnings("unchecked") + public List getApplyTo() { + return (List) super.getApplyTo(); + } + + @Override + public List getApplyTo(boolean create) { + return super.getApplyTo(SlotDefinition.class, create); + } + + @Override + public List getApplyTo(Class t) { + if ( !SlotDefinition.class.isAssignableFrom(t) ) { + throw new IllegalArgumentException("Invalid type parameter"); + } + return super.getApplyTo(t); + } + + @Override + public List getApplyTo(Class t, boolean create) { + if ( !SlotDefinition.class.isAssignableFrom(t) ) { + throw new IllegalArgumentException("Invalid type parameter"); + } + return super.getApplyTo(t, create); + } + + @Override + public void setApplyTo(List value) { + if ( value != null ) { + for ( Definition item : value ) { + if ( !(item instanceof SlotDefinition) ) { + throw new IllegalArgumentException("Invalid applyTo value"); + } + } + } + super.setApplyTo(value); + } + @Override public String toString() { return "SlotDefinition(name=" + this.getName() + ")"; diff --git a/pycodegen/javagen.py b/pycodegen/javagen.py index 82e49c8..06c006d 100644 --- a/pycodegen/javagen.py +++ b/pycodegen/javagen.py @@ -19,7 +19,7 @@ def cleanup_dir(directory): def cli(): # Generating test code - for name, package in [("samples", "base")]: + for name, package in [("samples", "base"), ("refined-inherited-slots", "refinhslot")]: output_dir = ROOT / "core/src/test/java/org/incenp/linkml/core/samples" / package cleanup_dir(output_dir) gen = JavaGenerator(ROOT / f"core/src/test/linkml/{name}.yaml",