I had to go through several combinations of attribute and constraint types before I had the PersistableAdapter worked out. When calling PersistableAdapter, it's a little tedious having to check whether the returned objects are arrays or not, as well as having to first check existing values when wanting to add or set values.
Add convenience methods to com.ptc.core.lwc.server.PersistableAdapter for casting, collection handling, and attribute value setting vs attribute value addition. The getter and setter is currently limited to public Object get(String attribute) and public Object set(String attribute, Object value).
public String getStringValue(String attribute)
public Set<String> getStringSet(String attribute)
public List<String> getStringList(String attribute)
public String getStringArray(String attribute)
public Timestamp getTimestampValue(String attribute)
public Set<Timestamp> getTimestampSet(String attribute)
public List<Timestamp> getTimestampList(String attribute)
public Timestamp getTimestampArray(String attribute)
public Number getNumberValue(String attribute)
public Set<Number> getNumberSet(String attribute)
public List<Number> getNumberList(String attribute)
public Number getNumberArray(String attribute)
public Double getDoubleValue(String attribute)
public Set<Double> getDoubleSet(String attribute)
public List<Double> getDoubleList(String attribute)
public Double getDoubleArray(String attribute)
The get*Value methods would simply attempt to cast the result as the requested type. If one called getNumberValue and the return type were a String, the call should fail with a ClassCastException. If the internal returned object were actually an Object array, maybe it would throw a ClassCast or an ArrayIndexOutOfBounds exception. I'm not sure there.
The get*Set methods would return a distinct set of the values. Maybe a LinkedHashSet. If the internal value were null or empty, an empty set would be returned. If the internal value was a single value and not an array, it would return a set with a single element.
The get*List methods would return an ArrayList containing all of the values. It would function similarly to the get*Set methods.
The get*Array methods would return an array, obviously. It would function similarly to the get*List and get*Set methods.
Null/empty values would be handled as follows. We'll use the StringValue class as our example. If getStringList("MyAttribute") references two StringValue records with record1.value being "xyz" and record2.value being null, it would return a List with list.get(0) returning "xyz" and list.get(1) returning null. If getStringList("MyAttribute" references zero StringValue records, an empty List would be returned. Where values are concerned, null is not the same as non-existent. The get*Set/List/Array methods would never return null.
I would also create add* methods maybe similar to the following:
public void addStringValue(String attribute, String...values)
public void addStringValue(String attribute, Collection<String> values)
public void addBooleanValue(String attribute, Boolean...values)
public void addBooleanValue(String attribute, Collection<Boolean> values)
I would create getters, setters, and adders for each of the attribute types. The internal mechanics of the setters/adders would check the constraints and throw the appropriate exceptions.