We are happy to announce version 3.1 of ObjectBox for Java and Kotlin. The major feature of this version is the new Flex type. For a long time, ObjectBox worked on rigid data schemas, and we think that this is a good thing. Knowing what your data looks like is a feature – similar to programming languages that are statically typed. Fixed schemas make data handling more predictable and robust. Nevertheless, sometimes there are use cases which require flexible data structures. ObjectBox 3.1 allows exactly this.
Flex properties
Expanding on the string and flexible map support in 3.0.0, this release adds support for Flex properties where the type must not be known at compile time. To add a Flex property to an entity use Object
in Java and Any?
in Kotlin. Then at runtime store any of the supported types.
For example, assume a customer entity with a tag property:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // Java @Entity public class Customer { @Id private long id; private Object tag; // TODO getter and setter } // Kotlin @Entity data class Customer( @Id var id: Long = 0, var tag: Any? = null ) |
Then set a String tag on one customer, and an Integer tag on another customer and just put them:
1 2 3 4 5 6 7 8 9 10 11 | // Java Customer customerStrTag = new Customer(); customerStrTag.setTag("string-tag"); Customer customerIntTag = new Customer(); customerIntTag.setTag(1234); box.put(customerStrTag, customerIntTag); // Kotlin val customerStrTag = Customer(tag = "string-tag") val customerIntTag = Customer(tag = 1234) box.put(customerStrTag, customerIntTag) |
When getting the customer from its box the original type is restored. For simplicity the below example just casts the tag to the expected type:
1 2 3 4 5 6 7 8 9 | // Java String stringTag = (String) box.get(customerStrTag.getId()).getTag(); Integer intTag = (Integer) box.get(customerIntTag.getId()).getTag(); // Kotlin val stringTag = box.get(customerStrTag.id).tag as String val intTag = box.get(customerIntTag.id).tag as Int |
A Flex property can be not justString or Integer. Supported types are all integers (Byte, Short, Integer, Long), floating point numbers (Float, Double), String and byte arrays.
It can also hold a List<Object> or a Map<String, Object> of those types. Lists and maps can be nested.
Behind the scenes Flex properties use a FlexBuffer converter to store the property value, so some limitations apply. See the FlexObjectConverter class documentation for details.
Query for map keys and values
If the Flex property contains integers or strings, or a list or map of those types, it’s also possible to do queries. For example, take this customer entity with a properties
String to String map:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // Java @Entity public class Customer { @Id private long id; private Map<String, String> properties; // TODO getter and setter } // Kotlin @Entity data class Customer( @Id var id: Long = 0, var properties: MutableMap<String, String>? = null ) |
Why is properties
not of type Object? ObjectBox supports using Map<String, String> (or Map<String, Object>) directly and will still create a Flex property behind the scenes.
Then put a customer with a premium property:
1 2 3 4 5 6 7 8 9 10 11 12 | // Java Customer customer = new Customer(); Map<String, String> properties = new HashMap<>(); properties.put("premium", "tier-1"); customer.setProperties(properties); box.put(customer); // Kotlin val customer = Customer( properties = mutableMapOf("premium" to "tier-1") ) box.put(customer) |
To query for any customers that have a premium key in their properties map, use the containsElement
condition:
1 2 3 4 5 6 7 8 9 10 | // Java Query<customer> queryPremiumAll = box.query( Customer_.properties.containsElement("premium") ).build(); // Kotlin val queryPremiumAll = box.query( Customer_.properties.containsElement("premium") ).build() </customer> |
Or to only match customers where the map key has a specific value, here a specific premium tier, use the containsKeyValue
condition:
1 2 3 4 5 6 7 8 9 10 | // Java Query<customer> queryPremiumTier1 = box.query( Customer_.properties.containsKeyValue("premium", "tier-1") ).build(); // Kotlin val queryPremiumTier1 = box.query( Customer_.properties.containsKeyValue("premium", "tier-1") ).build() </customer> |
What’s next?
ObjectBox database is free to use. Check out our docs and this video tutorial to get started today.
We strive to bring joy to mobile developers and appreciate all kinds feedback, both positive and negative. You can always raise an issue on GitHub or post a question on Stackoverflow. Otherwise, star the ObjectBox Java database GitHub repo and up-vote the features you’d like to see in the next release.