(Quick Reference)

2 Using the Smartionary Interface - Reference Documentation

Authors: Aaron Brown

Version: 1.0.0

2 Using the Smartionary Interface

From a progremmatic standpoint, the plugin tries to abstract the Smartionary domain into the overloaded Smartionary object. The Smartionary object provides an interface that abides by the following goals:
  • Be dyanamic
    • Automatically create Domains as necessary.
    • Update Domains that already exist.
  • Be flexible
    • Multiple ways to do the same thing.
    • Attempt to reduce the number of Exceptions that would occur.
  • Don't mind the illogical
    • Deleting a Domain that doesn't exist is just fine.
  • Pretend to be a Map
    • Treat interaction for the developer like they're working with a Map
    • Provide some Map-methods so they can be used without needing to work with an actual Map.

2.1 Setting

Creating and updating Domains is done via the set() method. There are several forms, but only the more complex (and flexible) ones will be discussed here.

Through all examples here use Strings, any Object can be used just like a Map. The caveat is that it gets converted to a String when placed in the Domain, and will be a String when retrieved.

See get() for details.

The primary strength of Smartionary is that it can convert a Map directly into a Smartionary domain:

Map toSmartionary = [
    a: "apple",
    b: "banana",
    c: "cantaloupe",
    d: "durian"
]

Smartionary.set(toSmartionary, 'fruits', 'A few fruits, by letter.')

That is a very straightforward approach, however just like when creating a Domain object, the method signature allows you to put the Map directly into the parameter body:

Smartionary.set(
    'fruits',
    'A few fruits, by letter',
    a: "apple",
    b: "banana",
    c: "cantaloupe",
    d: "durian")

In the above sample, the description was moved to be the second positional parameter. This makes it a bit more readable than the explicit form.

In the above case, set() does the following:

  1. Retrieve the Smartionary that exists by the name of fruits .
    • If it does not exist, create it.
  1. Replace the values in the corresponding SmartionaryEntries.
    • If it does not exist, create it.

Therefore, the same Smartionary domain can be updated with a successive call, and a subset of values can be replaced, and others can be added:

Smartionary.set(
    'fruits',
    c: "cherry",
    t: "tomato",
    w: "watermelon")

By using this method, it is impossible to encounter the unique naming constraints.

Due to the nature of setting, be very mindful if you wish to only update the description . For more information, read about setting Smartionary descriptons

Setting from JSON

An extension of the set() method is the fromJson() method. This provides a convenient way of converting a JSON string which would describe a set of parameters or criteria into an equivalent Smartionary.

String json = '{"a": "apple", "b": "banana", "c": "carrot", "d": "durian"}'

Smartionary.set('fruits', json, 'A few fruits, by letter.')

json = '{"c": "cherry", "t": "tomato", "w": "watermelon"}'

Smartionary.set('fruits', json)

Note that the order of the parameters differs. It is not shown here, but in all instances of set(), the smartionaryName is the first parameter with the exception of the example above. This is due to the way Groovy handles that particular method signature. {warn}

When working with JSON, an array such as the following is not supported:

'["apple", "banana", "cantaloupe", "durian"]'

This will throw an IllegalArgumentException.

null

Nested Maps and Lists inside the JSON will be converted to Strings, so this is not very appropriate for complex schemas.

2.1.1 Setting Descriptions

There are certain considerations to bear in mind when it comes to the descriptions of Smartionary and SmartionaryEntry. Both Domains allow for a description, which is primarily for when looking at the view. While developing, it is best-practice to put some form of description with the instances, even though the Smartionary has no methods to retrieve them.

Smartionary Description

The description for a Smartionary can be set using any form of the set() method. There is no harm in omitting the description; if the domain already has one, it will keep it.

SmartionaryEntry Description

The description for a SmartionaryEntry can only be updated (via the Smartionary) by the set() methods (or fromJson()). The explicit methods are fairly starightforward, but for the named-parameter signature there is a specific way:

Smartionary.set(
    'fruits',
    a: "apple",
    b: "banana",
    c: "cantaloupe",
    d: "durian",
    smartionaryDescriptions: [
        a: "Can be green, yellow, or red; sour or sweet.",
        b: 'Grows in bunches, called "hands."',
        c: "A kind of melon with a lattuce skin.",
        d: "A spiney fruit like a pineapple, that's really stinky.",
        t: "A red, fragile bulb; debated to be a vegetable."
    ]
)

The smartionaryDescriptions key is sort of a "reserved" key for this method. It follows a simple rule: only update the keys that appear in the outer Map . In this example, the key t does not appear in the outer Map, therefore, even if a SmartionaryEntry exists for t, it will not be updated.

The rationality behind this is two-fold:

  1. Enforces awareness of value modification
  2. Prevents accidental and ambiguous behavior when dealing with null.

This behavior applies to all versions of set() (as well as fromJson()). If it is necessary to update only the description, it is best and safer to use the web-interface.

Should you choose to update the descriptions through the Smartionary, be aware that if you pass null for the value of that key, then that is what will be written to the Domain.

2.2 Getting

Accessing the information in a Smartionary domain progremmatically is done via the get() method.

The get() method does not automatically create a Smartionary domain if it does not exist (that can only be done by the set() methods).

Map data = Smartionary.get('fruits')

Depending on the state of the Domain, the following conditions apply:

Smartionary existsHas SmartionaryEntriesReturns
  null
 [:]
a=apple, b=banana, c=cantaloupe, d=durian

The philosophy behind the plugin is that get() is used more frequently than set(). While it may be tempting to cache or somehow store the information, that ruins the advantages of being able to change the values of a Smartionary while in production, on-the-fly. Therefore, the following is not best practice:

class MyClass {
    Map myInfo = Smartionary.get('myInfoParams')

private final static MyInfo INSTANCE = new MyInfo()

private myInfo() { }

static getInstance() { return INSTANCE } }

The contents of myInfo can only be updated on application restart.

Getting as JSON

Just like withJson() there is a method for retrieving a Smartionary as a JSON string directly. It uses the internal Groovy JsonBuilder to fascilitate this:

try {
    Smartionary.getAsJson('fruits')
} catch (IllegalArgumentException e) {
    // The Smartionary may not exist.
} catch (JsonException e) {
    // Something went awry.
}

Please note the try/catch statement.

Since the JsonBuilder is used, by passing true (or explicitly false) you can specify that the String should (not) be pretty-formatted:

try {
    Smartionary.getAsJson('fruits', true)
} catch (IllegalArgumentException e) {
    // The Smartionary may not exist.
} catch (JsonException e) {
    // Something went awry.
}

2.3 Map-like Interface

The Smartionary comes with several basic Map-like functions, so that some operations can be performed directly, rather than making it necessary to retrieve Map through getting

They are exactly like their Map counterpart, with one exception.

Methodexample
contains
Smartionary.contains('fruits', 'apple')
containsKey
Smartionary.containsKey('fruits', 'a')
size
Smartionary.size('fruits')

The exception to this rule is the size() method:

ConditionResult
Smartionary does not exist-1
Smartionary exists, but SmartionaryEntries do not0
OtherwiseNormal size() behavior for Map.