Further to this, I've updated the kitchensink (against 1.9.0-SNAPSHOT) to demonstrate this technique....
The code is in ReferenceObject, which you can get to from the "Data Types" menu. Use the fixture scripts menu to create some sample data. The relevant code is below. Cheers Dan [1] https://github.com/isisaddons/isis-app-kitchensink private OtherObject someOtherObjectUsingName; @Property(hidden = Where.EVERYWHERE) @Column(allowsNull = "true") public OtherObject getSomeOtherObjectUsingName() { return someOtherObjectUsingName; } public void setSomeOtherObjectUsingName(final OtherObject someOtherObjectUsingName) { this.someOtherObjectUsingName = someOtherObjectUsingName; } @NotPersistent public String getSomeOtherObjectUsingNameName() { return getSomeOtherObjectUsingName() != null? getSomeOtherObjectUsingName().getName() : null; } public void setSomeOtherObjectUsingNameName(final String name) { OtherObject otherObject = name != null ? container.firstMatch(OtherObject.class, withName(name)) : null; setSomeOtherObjectUsingName(otherObject); } public List<String> choicesSomeOtherObjectUsingNameName() { List<OtherObject> otherObjects = container.allInstances(OtherObject.class); return Lists.newArrayList( Iterables.transform(otherObjects, nameOf()) ); } private static Function<OtherObject, String> nameOf() { return new Function<OtherObject, String>() { @Nullable @Override public String apply(final OtherObject input) { return input.getName(); } }; } private static Predicate<OtherObject> withName(final String name) { return new Predicate<OtherObject>() { @Override public boolean apply(final OtherObject input) { return Objects.equal(input.getName(), name); } }; } On 30 July 2015 at 13:16, Dan Haywood <[email protected]> wrote: > looks right to me, so I'll take a look at in this eve or tomorrow. > > thx > Dan > > > On 30 July 2015 at 13:12, Stephen Cameron <[email protected]> > wrote: > >> Still no luck with this one. >> >> The derived RegionName appears as a non-editable property, so not sure >> what >> was different before when I was getting an model validation error. >> >> My current code of interest is this: >> >> @Column(name = "region", allowsNull = "true") >> //@MemberOrder(sequence = "7") >> @Property(hidden=Where.EVERYWHERE) >> public Region getRegion() { >> return this.region; >> } >> >> public void setRegion(Region region) { >> this.region = region; >> } >> >> public List<Region> choicesRegion() { >> return regions.listAllRegions(); >> } >> >> @MemberOrder(sequence = "7") >> public String getRegionName() { >> return regions.nameForRegion(getRegion()); >> } >> >> public void setRegionName(String name) { >> setRegion(regions.regionForName(name)); >> } >> >> public List<String> choicesRegionName(){ >> return regions.listAllNamesExclusive(getRegion()); >> } >> >> My Region class is this: >> >> package au.com.scds.chats.dom.modules.general.codes; >> >> import javax.jdo.annotations.Column; >> import javax.jdo.annotations.IdentityType; >> import javax.jdo.annotations.PrimaryKey; >> >> import org.apache.isis.applib.annotation.Action; >> import org.apache.isis.applib.annotation.ActionLayout; >> import org.apache.isis.applib.annotation.DomainServiceLayout; >> import org.apache.isis.applib.annotation.DomainServiceLayout.MenuBar; >> import org.apache.isis.applib.annotation.MemberOrder; >> import org.apache.isis.applib.annotation.PropertyLayout; >> >> @javax.jdo.annotations.PersistenceCapable( >> identityType=IdentityType.APPLICATION) >> public class Region { >> >> public String title(){ >> return getName(); >> } >> >> private String name; >> >> @Column(name="region", allowsNull = "false") >> @PrimaryKey() >> @PropertyLayout(named="Region") >> @MemberOrder(sequence="1") >> public String getName() { >> return name; >> } >> >> public void setName(String name) { >> this.name = name; >> } >> } >> >> My Regions repository class is this: >> >> package au.com.scds.chats.dom.modules.general.codes; >> >> import java.util.ArrayList; >> import java.util.List; >> >> import org.apache.isis.applib.DomainObjectContainer; >> import org.apache.isis.applib.annotation.Action; >> import org.apache.isis.applib.annotation.ActionLayout; >> import org.apache.isis.applib.annotation.BookmarkPolicy; >> import org.apache.isis.applib.annotation.DomainService; >> import org.apache.isis.applib.annotation.DomainServiceLayout; >> import org.apache.isis.applib.annotation.DomainServiceLayout.MenuBar; >> import org.apache.isis.applib.annotation.MemberOrder; >> import org.apache.isis.applib.annotation.ParameterLayout; >> import org.apache.isis.applib.annotation.Programmatic; >> import org.apache.isis.applib.annotation.SemanticsOf; >> import org.apache.isis.applib.query.QueryDefault; >> >> import au.com.scds.chats.dom.modules.participant.Participant; >> >> @DomainService(repositoryFor = Region.class) >> @DomainServiceLayout(menuBar = MenuBar.SECONDARY, named = >> "Administration", >> menuOrder = "100.1") >> public class Regions { >> >> // region > listAll (action) >> @Action(semantics = SemanticsOf.SAFE) >> @ActionLayout(bookmarking = BookmarkPolicy.AS_ROOT) >> @MemberOrder(sequence = "1") >> public List<Region> listAllRegions() { >> return container.allInstances(Region.class); >> } >> >> // endregion >> >> // region > create (action) >> @MemberOrder(sequence = "2") >> public Region createRegion( >> final @ParameterLayout(named = "Region Name") String name) { >> final Region obj = container.newTransientInstance(Region.class); >> obj.setName(name); >> container.persistIfNotAlready(obj); >> return obj; >> } >> >> // endregion >> >> // region > injected services >> >> @javax.inject.Inject >> DomainObjectContainer container; >> >> // endregion >> >> @Programmatic >> public String nameForRegion(Region region) { >> return (region != null) ? region.getName() : null; >> } >> >> >> @Programmatic >> public List<String> listAllNamesExclusive(Region region) { >> List<Region> regions = listAllRegions(); >> List<String> names = new ArrayList<String>(); >> for (Region r : regions) { >> if (region != null && r != region) { >> names.add(r.getName()); >> } >> } >> return names; >> } >> >> >> @Programmatic >> public Region regionForName(String name) { >> Region region = container.firstMatch(new QueryDefault<>( >> Region.class, >> "findRegion", "name", name)); >> return region; >> } >> >> } >> >> Just maybe I there is something missing still? >> >> I added a @Property annotation to the getRegionName() method, but that >> gave >> me a message saying it expected @javax.jdo.persistence.Column too. >> >> Note I couldn't use deprecated @Hidden in Isis 1.9.0. >> >> >> On Thu, Jul 30, 2015 at 8:14 PM, Stephen Cameron < >> [email protected] >> > wrote: >> >> > Hi Dan, When I tried this I got an model validation error message >> relating >> > to the choices method, I will have another go and if it fails, provide >> the >> > test case. Thanks for the tips. >> > >> > On Thu, Jul 30, 2015 at 7:57 PM, Dan Haywood < >> [email protected] >> > > wrote: >> > >> >> You should be able to add a choicesXxx() for the derived property: >> >> >> >> public List<String> choicesRegionName(){ >> >> return Lists.newArrayList(Iterables.transform(choicesRegion(), >> x >> >> -> >> >> x.getName())); >> >> } >> >> >> >> If that isn't sufficient, you might also need to add a setter: >> >> >> >> public void setRegionName(final String name) { >> >> setRegion(Iterables.find(choicesRegion(), x -> >> x.getName().equals(name))); >> >> } >> >> >> >> Obviously, you might need to also add some error handling. >> >> >> >> ~~~ >> >> >> >> Regarding the "external URL" idea, perhaps you could raise that as a >> >> separate ticket, with a code sketch as to how you'd like this >> information >> >> specified? >> >> >> >> Thanks >> >> Dan >> >> >> >> >> >> >> >> >> >> >> >> On 30 July 2015 at 03:17, Stephen Cameron <[email protected]> >> >> wrote: >> >> >> >> > Not so simple, as now the property cannot be updated. >> >> > >> >> > I have the following (@Hidden is deprecated) >> >> > >> >> > @Column(allowsNull = "true") >> >> > @MemberOrder(sequence = "7") >> >> > @PropertyLayout(hidden=Where.EVERYWHERE) >> >> > public Region getRegion() { >> >> > return this.region; >> >> > } >> >> > >> >> > public void setRegion(Region region) { >> >> > this.region = region; >> >> > } >> >> > >> >> > public List<Region> choicesRegion(){ >> >> > List<Region> regions = container.allInstances(Region.class); >> >> > return regions; >> >> > } >> >> > >> >> > @MemberOrder(sequence = "7.1") >> >> > public String getRegionName(){ >> >> > return (getRegion() != null) ? getRegion().getName() : null; >> >> > } >> >> > >> >> > Sure enough getRegion doesn't appear in the UI but getRegionName >> does, >> >> but >> >> > then setRegion and choiceRegion don't mean anything to the UI, so the >> >> > Region property is read-only. >> >> > >> >> > This issue is maybe more significant than it appears at first, in >> terms >> >> of >> >> > domain modelling such code-lists are simple types that 'represent' >> >> things >> >> > on the boundary of the domain of interest. So we usually want to just >> >> > represent them with a name. Presently it makes no sense to go to that >> >> thing >> >> > via a hyperlink as all we'll find is that name, our model extends no >> >> > further. >> >> > >> >> > However we just might like to allow users to leave the domain model >> and >> >> go >> >> > to a resource outside. So, extending the suppressLink=true idea, I >> would >> >> > add that each object could have an implicit link(URL),created by >> Isis, >> >> or >> >> > an explicit one and if the explicit one is present it can optionally >> be >> >> > used as an alternative to the implicit one. >> >> > >> >> > For example, you might create a database to log fish details, species >> >> is a >> >> > boundary concept, we aren't likely to want to add a new species to >> the >> >> list >> >> > of known species, but we'd like to keep such a list handy, but for >> each >> >> > named species in that list, to provide an explicit link to a resource >> >> in a >> >> > global fish database. It makes more sense to use this link than the >> >> > implicit one, as if the implicit one is used we'd navigate to the >> domain >> >> > object page displaying the name and URL, both of which items of data >> >> could >> >> > have been in the explicit link. >> >> > >> >> > In the explicit case you might want to warn the user they are >> navigating >> >> > outside the Isis domain application. >> >> > >> >> > Perhaps all this could be done simply if there was a URI type in >> Isis, >> >> that >> >> > would allow it to create 'smart links' automatically. >> >> > >> >> > >> >> > >> >> > >> >> > >> >> > On Wed, Jul 29, 2015 at 9:37 PM, Stephen Cameron < >> >> > [email protected] >> >> > > wrote: >> >> > >> >> > > Thanks Jeroen, seems simple enough :) >> >> > > >> >> > > On Wed, Jul 29, 2015 at 9:28 PM, Jeroen van der Wal < >> >> [email protected] >> >> > > >> >> > > wrote: >> >> > > >> >> > >> You could also hide the property and create a separate getter for >> >> > display >> >> > >> purposes only: >> >> > >> >> >> > >> private MyProperty myProperty; >> >> > >> >> >> > >> @Hidden >> >> > >> public MyProperty getMyProperty() {...} >> >> > >> >> >> > >> public void setMyProperty(...) {...} >> >> > >> >> >> > >> public String getMyPropertyName() { >> >> > >> getMyProperty.getName(); >> >> > >> } >> >> > >> >> >> > >> On 29 July 2015 at 13:18, Stephen Cameron < >> >> [email protected]> >> >> > >> wrote: >> >> > >> >> >> > >> > On Wed, Jul 29, 2015 at 6:38 PM, Dan Haywood < >> >> > >> [email protected] >> >> > >> > > >> >> > >> > wrote: >> >> > >> > >> >> > >> > > You are right, they will be displayed as links; there's no >> way to >> >> > >> disable >> >> > >> > > it currently. >> >> > >> > > >> >> > >> > > We could add a bit of metadata perhaps for this, eg >> >> > >> > > @DomainObjectLayout(suppressLink=true) or similar. >> >> > >> > > >> >> > >> > > Please raise a ticket. >> >> > >> > > >> >> > >> > >> >> > >> > OK https://issues.apache.org/jira/browse/ISIS-1180 >> >> > >> > >> >> > >> > > >> >> > >> > > Thx >> >> > >> > > Dan >> >> > >> > > >> >> > >> > > PS: these entities wouldn't be value types, rather regular >> >> entities. >> >> > >> But >> >> > >> > > you are right... what we really want is full-class support for >> >> value >> >> > >> > types. >> >> > >> > > We're just not there yet... >> >> > >> > > >> >> > >> > > >> >> > >> > > >> >> > >> > >> >> > >> > > >> >> > >> > > >> >> > >> > > On 29 July 2015 at 09:34, Stephen Cameron < >> >> > [email protected] >> >> > >> > >> >> > >> > > wrote: >> >> > >> > > >> >> > >> > > > Thanks, but surely such object properties always end up >> being >> >> > >> displayed >> >> > >> > > as >> >> > >> > > > links? Clicking on the link to go to such an object page is >> >> > >> > meaningless, >> >> > >> > > as >> >> > >> > > > it only has one name property, that was displayed in the >> link. >> >> > Can I >> >> > >> > > > disable that default behaviour for value types? >> >> > >> > > > >> >> > >> > > > >> >> > >> > > > >> >> > >> > > > On Wed, Jul 29, 2015 at 5:47 PM, Dan Haywood < >> >> > >> > > [email protected] >> >> > >> > > > > >> >> > >> > > > wrote: >> >> > >> > > > >> >> > >> > > > > On 29 July 2015 at 08:08, Stephen Cameron < >> >> > >> > [email protected]> >> >> > >> >> >> > >> > > > > wrote: >> >> > >> > > > > >> >> > >> > > > > > Hi, >> >> > >> > > > > > >> >> > >> > > > > > I want to do have some properties that are essentially >> >> String >> >> > >> > types, >> >> > >> > > > but >> >> > >> > > > > > which have a limited range of values (code-lists or >> >> restricted >> >> > >> > > > > > vocabularies). I want to allow these lists to be >> >> administered >> >> > >> > > > centrally, >> >> > >> > > > > so >> >> > >> > > > > > to add them to a single Administration menu item for >> admin >> >> > >> users. >> >> > >> > > > > > >> >> > >> > > > > > For most users these codes should appears as lists of >> >> strings >> >> > >> not >> >> > >> > as >> >> > >> > > > > > objects, but making them objects seems to be the >> logical OO >> >> > way >> >> > >> to >> >> > >> > > deal >> >> > >> > > > > > with them in Isis. So they are basically objects with >> one >> >> > 'name' >> >> > >> > > > property >> >> > >> > > > > > (and maybe an id added by datanucleus). All users need >> to >> >> see >> >> > is >> >> > >> > the >> >> > >> > > > name >> >> > >> > > > > > property, no icon is needed. >> >> > >> > > > > > >> >> > >> > > > > > Also, if I make them objects I also will get referencial >> >> > >> integrity >> >> > >> > > > > > constraints applied in the database. >> >> > >> > > > > > >> >> > >> > > > > > >> >> > >> > > > > +1, do it this way. That way they can also hold >> behaviour in >> >> > the >> >> > >> > > future. >> >> > >> > > > > >> >> > >> > > > > >> >> > >> > > > > >> >> > >> > > > > >> >> > >> > > > > > I wonder there is a simple recipe for this? >> >> > >> > > > > > >> >> > >> > > > > >> >> > >> > > > > No magic recipe for the domain entities... basically >> >> > copy-n-paste >> >> > >> the >> >> > >> > > > > SimpleObject that's in our archetype as many times as >> needed, >> >> > and >> >> > >> > tweak >> >> > >> > > > as >> >> > >> > > > > required. >> >> > >> > > > > >> >> > >> > > > > If you want to use the code as the primary key, then use >> DN >> >> > >> > application >> >> > >> > > > > identity >> >> > >> > > > > >> >> > >> > > > > @javax.jdo.annotations.PersistenceCapable( >> >> > >> > > > > identityType=IdentityType.APPLICATION, >> >> > >> > > > > schema = "simple", >> >> > >> > > > > table = "SimpleObject" >> >> > >> > > > > ) >> >> > >> > > > > >> >> > >> > > > > and add @PrimaryKey to the "name" property. Also add >> @Title >> >> to >> >> > >> that >> >> > >> > > > 'name' >> >> > >> > > > > property (it is in SimpleObject already). >> >> > >> > > > > >> >> > >> > > > > >> >> > >> > > > > You would probably want to remove the version column, ie >> >> remove: >> >> > >> > > > > >> >> > >> > > > > @javax.jdo.annotations.Version( >> >> > >> > > > > strategy=VersionStrategy.VERSION_NUMBER, >> >> > >> > > > > column="version") >> >> > >> > > > > >> >> > >> > > > > >> >> > >> > > > > In addition, if you annotate the class as "bounded" >> >> > >> > > > > (@DomainObject(bounded=true)) then you are telling the >> >> framework >> >> > >> that >> >> > >> > > > > there's a limited - ie bounded - set of instances, and so >> it >> >> > will >> >> > >> > > display >> >> > >> > > > > all instances in a drop-down for you. >> >> > >> > > > > >> >> > >> > > > > >> >> > >> > > > > HTH >> >> > >> > > > > Dan >> >> > >> > > > > >> >> > >> > > > >> >> > >> > > >> >> > >> > >> >> > >> >> >> > > >> >> > > >> >> > >> >> >> > >> > >> > >
