Gauvain Klug
Gauvain Klug

Reputation: 591

Property's setLabel cause NPE

I'm trying the BoundTableModel for the first time, and when I tried to set the labels of my properties, I've got a NullPointerException.

[EDT] 0:0:8,239 - Exception: java.lang.NullPointerException - null
java.lang.NullPointerException
    at com.codename1.properties.PropertyBase.putClientProperty(PropertyBase.java:131)
    at com.codename1.properties.PropertyBase.setLabel(PropertyBase.java:192)
    at our.app.forms.UnitsForm.<init>(UnitsForm.java:54)

The NPE is throwed in this code block, but I don't understand why. The properties are public final and instanciated within the UserHistory, but no label are set there. It's better to set them later, as they need to be translated by our TranslationManager.

UiBinding ui = new UiBinding();
List<UserHistory> histories = RestManager.getHistory();
UserHistory prototype = new UserHistory();
prototype.dateCreate.setLabel("Date"); 
prototype.balanceUpdate.setLabel("Variation"); 
prototype.action.setLabel("Action");

UiBinding.BoundTableModel tb = ui.createTableModel(histories, prototype);
tb.setColumnOrder(prototype.dateCreate, prototype.balanceUpdate, prototype.action);
Table table = new Table(tb);

I don't understand how the setLabel(String) of Property can throw a NullPointerException, any idea ?

EDIT: Here are the classes which fails, the first is the AbstractEntity:

public abstract class AbstractEntity implements Serializable, PropertyBusinessObject 
{
    public final LongProperty<AbstractEntity> id = new LongProperty<>("id");

    public final IntProperty<AbstractEntity> version = new IntProperty<>("version");

    public final Property<Date, AbstractEntity> dateCreate = new Property<>("dateCreate", Date.class);

    public final Property<Date, AbstractEntity> dateUpdate = new Property<>("dateUpdate", Date.class);

    protected List<PropertyBase> getPropertyList() 
    {
        List<PropertyBase> list = new ArrayList<>();
        list.add(id);
        list.add(version);
        list.add(dateCreate);
        list.add(dateUpdate);
        return list;
    }

    protected List<PropertyBase> getExcludePropertyList()
    {
        List<PropertyBase> list = new ArrayList<>();
        return list;
    }

    @Override
    public PropertyIndex getPropertyIndex()
    {
        PropertyBase[] properties = getPropertyList().toArray(new PropertyBase[getPropertyList().size()]);
        PropertyIndex index =  new PropertyIndex(this, getName(), properties);

        for(PropertyBase excluded : getExcludePropertyList())
        {
            index.setExcludeFromJSON(excluded, true);
            index.setExcludeFromMap(excluded, true);
        }

        return index;
    }
}

And here is the child class which I tried to show in a table:

public class UserHistory extends AbstractEntity 
{

    public final Property<User, UserHistory> user = new Property<>("user", User.class);

    public final DoubleProperty<UserHistory> balanceUpdate = new DoubleProperty<>("balanceUpdate");

    public final Property<String, UserHistory> action = new Property<>("action");

    public UserHistory() {}

    @SuppressWarnings("rawtypes")
    protected List<PropertyBase> getPropertyList() 
    {
        List<PropertyBase> list = super.getPropertyList();
        list.add(user);
        list.add(balanceUpdate);
        list.add(action);
        return list;
    }
}

Upvotes: 1

Views: 37

Answers (1)

Shai Almog
Shai Almog

Reputation: 52760

This won't work.

Your approach is interesting but it behaves differently from the common implementation in one significant way: the index is created lazily. So initialization work done by the index doesn't actually happen in all cases.

Worse, you create multiple indexes every time the get method is called which is also problematic.

Something that "might" work is this:

public abstract class AbstractEntity implements Serializable, PropertyBusinessObject 
{
    public final LongProperty<AbstractEntity> id = new LongProperty<>("id");

    public final IntProperty<AbstractEntity> version = new IntProperty<>("version");

    public final Property<Date, AbstractEntity> dateCreate = new Property<>("dateCreate", Date.class);

    public final Property<Date, AbstractEntity> dateUpdate = new Property<>("dateUpdate", Date.class);

    private PropertyIndex index;


    protected AbstractEntity() {
        getPropertyIndex();
    }

    protected List<PropertyBase> getPropertyList() 
    {
        List<PropertyBase> list = new ArrayList<>();
        list.add(id);
        list.add(version);
        list.add(dateCreate);
        list.add(dateUpdate);
        return list;
    }

    protected List<PropertyBase> getExcludePropertyList()
    {
        List<PropertyBase> list = new ArrayList<>();
        return list;
    }

    @Override
    public PropertyIndex getPropertyIndex()
    {
        if(idx == null) {
            PropertyBase[] properties = getPropertyList().toArray(new PropertyBase[getPropertyList().size()]);
            index =  new PropertyIndex(this, getName(), properties);

            for(PropertyBase excluded : getExcludePropertyList())
            {
                index.setExcludeFromJSON(excluded, true);
                index.setExcludeFromMap(excluded, true);
            }
        }
        return index;
     }
}

Original answer below:

This happens if you forgot to add the property to the index object. In that case the parent object is null and meta-data can't be set.

Upvotes: 1

Related Questions