yngling yngling - 2 months ago 8
Java Question

Why are array contents of a core datastore type not stored in app engine?

I have the following issue:

A java object contains two arrays of core datastore types (com.google.appengine.api.datastore.Text and java.util.Date), plus an int (for storing the current populated position in the arrays) and some other fields.

I believe the documentation states that arrays of core datatypes should be ok (cf. http://code.google.com/appengine/docs/java/datastore/jdo/dataclasses.html, under the "Class and Field Annotations").

The object is updated using a method named "updateAnswer". When this method is called, the object is indeed updated (the int is incremented and stored correctly), but the arrays never store anything but nulls.

I would greatly appreciate it if someone could point out where my mistake lies.

Here is the object (and its parent, for completeness):

@PersistenceCapable
public class TextualAnswer extends Answer {

@Persistent
private Text textAnswer;

@Persistent
private Date date;

@Persistent
private int pos;

@Persistent
private Text texts[];

@Persistent
private Date dates[];

public TextualAnswer(Key question, Key user, Date date) {
super(question, user, 0);
this.textAnswer = null;
this.date = date;
pos = 0;
texts = new Text[20];
dates = new Date[20];
}

public String getTextAnswer() {
return (textAnswer != null ? textAnswer.getValue() : null);
}

public Date getDate() {
return date;
}

public void updateAnswer(String textAnswer, Date date) {
if (texts.length == pos) { // expand?
Text ttemp[] = texts;
texts = new Text[pos * 2];
System.arraycopy(ttemp, 0, texts, 0, pos);

Date dtemp[] = dates;
dates = new Date[pos * 2];
System.arraycopy(dtemp, 0, dates, 0, pos);
}
texts[pos] = this.textAnswer;
dates[pos] = this.date;
pos++;

this.textAnswer = (textAnswer != null ? new Text(textAnswer) : null);
this.date = date;
}
}


The parent:

@PersistenceCapable
@Inheritance(strategy = InheritanceStrategy.SUBCLASS_TABLE)
public abstract class Answer {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;

@Persistent
private Key question;

@Persistent
private Key user;

@Persistent
private double score;

@Persistent
private boolean last;

@Persistent
private Text comment;

public Answer(Key question, Key user, double score) {
this.question = question;
this.user = user;
this.score = score;
last = false;
comment = null;
}

public Key getKey() {
return key;
}

public Key getQuestion() {
return question;
}

public Key getUser() {
return user;
}

public double getScore() {
return score;
}

public boolean isLast() {
return last;
}

public String getComment() {
return comment != null ? comment.getValue() : null;
}

public void setScore(double score) {
this.score = score;
}

public void setLast(boolean last) {
this.last = last;
}

public void setComment(String comment) {
this.comment = comment != null ? new Text(comment) : null;
}
}


A closing note. I realize I could use Lists etc instead, and if I do not figure this out that is indeed my backup plan. But, I would like to realize why this isn't working, so I'd love any suggestions that I switch to objects instead of arrays to be accompanied with an explanation as to why the arrays are not working ;) Thank you.

Ex animo, - Alexander Yngling

Answer

So, after some sleep it occurred to me... it's an array index. I'm using JDO. I'm an idiot ;)

I thought about deleting this question, but just in case someone else searches for this, here's the problem:

http://www.datanucleus.org/products/datanucleus/jdo/orm/arrays.html

JDO cannot know that an array index has been updated, so you have to either set the field again, or use the following to tell JDO to update the database:

JDOHelper.makeDirty(obj, "fieldName");