12

I have the following java model class in App Engine:

public class Xyz ... {
    @Persistent
    private Set<Long> uvw;
}

When saving an object Xyz with an empty set uvw in Java, I get a "null" field (as listed in the appengine datastore viewer). When I try to load the same object in Python (through remote_api), as defined by the following python model class:

class Xyz(db.Model):
    uvw = db.ListProperty(int)

I get a "BadValueError: Property uvw is required".

When saving another object of the same class in Python with an empty uvw list, the Datastore viewer prints a "missing" field.

Apparently empty lists storage handling differs between Java and Python and lead to "incompatible" objects.

Thus my question: Is there a way to, either:

  • force Java to store an empty list as a "missing" field,
  • force Python to gracefully accept a "null" list as an empty list when loading the object?

Or any other suggestion on how to handle empty list field in both languages.

Thanks for your answers!

Deniss T.
  • 2,526
  • 9
  • 21
Laurent Grégoire
  • 4,006
  • 29
  • 52
  • 1
    https://cloud.google.com/appengine/docs/legacy/standard/java/datastore/entity-property-reference – Teddy Mar 11 '23 at 03:42

4 Answers4

2

It should work if you assign a default value to your Python property:

uvw = db.ListProperty(int, default=[])
Claude Vedovini
  • 2,421
  • 21
  • 19
1

I use the low-level java api, so perhaps what I am doing would be different. But before I save a collection-type data structure to the datastore, I convert it into something that the datastore naturally handles. This would include mainly Strings and ByteArrays.

It sounds like java app engine is interpreting the empty set as a null value. And python is not reading this null value correctly. You might try saving an empty set as the String value "empty set". And then have python check to see if the datastore holds that string value. If it does, it could allocate a new empty set, if not, it could read the property as a set.

Chris Dutrow
  • 48,402
  • 65
  • 188
  • 258
0

The Java Set behavior is because Java's Collections are reference types, which default to being null.

To actually create an empty Set, declare it like this:

@Persistent
private Set<Long> uvw = new HashSet<Long>();

or using some other implementation of Set on the right side. HashSet is the most commonly used Set type, though. Other interesting set types are the two thread-safe Sets CopyOnWriteArraySet and ConcurrentSkipListSet; also the Ordered Set type LinkedHashSet and the Sorted Set type TreeSet.

Powerlord
  • 87,612
  • 17
  • 125
  • 175
  • 2
    Thanks, but when I save the object to the datastore the set is *empty*, not *null* (my code is not clear, I should have specified that before storing the object the set is an empty HashSet). The trick here is that the appengine datastore layer seems to convert empty set to "null" values when storing, and I don't see any control on this behavior. – Laurent Grégoire Feb 23 '10 at 09:39
  • @IOranger: Ah, OK. I was going to delete this answer, but I'll leave it here so someone else doesn't come by later and say the same thing. – Powerlord Feb 23 '10 at 14:47
  • 1
    @LaurentGrégoire At least now there is a way to control this behaviour! To change default behavior so you can use empty lists, set the DATASTORE_EMPTY_LIST_SUPPORT property during your app initialization as follows: – Teddy Mar 11 '23 at 03:42
  • https://cloud.google.com/appengine/docs/legacy/standard/java/datastore/entity-property-reference – Teddy Mar 11 '23 at 03:42
0

It may work to you

uvw = db.ListProperty(int, default=[])

Its the most comment way to short it out...

Raju
  • 1
  • 3