ActiveWeb: model setter/getter does not work when calling in the template

724 views Asked by At

When working with a legacy database, there are cases when I can't set up the relations properly using belongs_to annotation. In this case, I tried to define an attribute pointing to another Model class with its accessors methods as follows:

@Table("INTERVENTION")
@IdName("ITV_ID")
public class Intervention extends Model {
  private InterventionModel interventionModel;

    public InterventionModel getInterventionModel() {
        return interventionModel;
    }

    public void setInterventionModel(InterventionModel interventionModel) {
        this.interventionModel = interventionModel;
    }
}

I'm loading and setting InterventionModelin a service class without problems as follows (intervention instance exists):

private void loadInterventionModel(final Intervention intervention) {
        final InterventionModel model = InterventionModel.findById(intervention.getLongId());
        intervention.setInterventionModel(model);
    }

The problem is that it does not work when I try to assess InterventionModel attributes in the FreeMarker template:

"item_code:": ${intervention.intervention_model.imo_internal_code}

Here is the flushed error:

FreeMarker template error:
An error has occurred when reading existing sub-variable "intervention_model"; see cause exception! The type of the containing value was: extended_hash+string (app.models.Intervention wrapped into f.e.b.StringModel)

Caused by: java.lang.IllegalArgumentException: Attribute: 'intervention_model' is not defined in model: 'class app.models.Intervention.

What am I missing here and why it does not work as expected ? Generally, if I declare an attribute in the model with its accessors (getter and setter), will it be accessible in the template with:

mymodel.my_attribute
2

There are 2 answers

0
belgoros On

I think, I found the reason. It seems like when you declare an instance variable in the class model and this variable does not belongs to the model available attributes (table columns), you should use snake_case instead of camelCase writing, i.e. instead of declaring:

public class Intervention extends Model {
...
  private InterventionModel interventionModel;

  public InterventionModel getInterventionModel() {
        return interventionModel;
    }

    public void setInterventionModel(InterventionModel interventionModel) {
        this.interventionModel = interventionModel;
    }

}

use a snake_case version:

private InterventionModel intervention_model;

public InterventionModel getIntervention_model() {
    return intervention_model;
}

public void setIntervention_model(InterventionModel intervention_model) {
    this.intervention_model = intervention_model;
}

This way you will be able to access it in the template as others variables available in the model:

"label": "${intervention.intervention_model.imo_product_label}"

In the beginning, I believed that the conversion was done automatically. You can keep camlCase verion, - in this case you should use it in your template as well:

"label": "${intervention.interventionModel.imo_product_label}"

Hope this helps.

1
ipolevoy On

If your class InterventionModel points to a legacy table, you can do this:

@Table("INTERVENTION")
@IdName("ITV_ID")
public class Intervention extends Model {
  private InterventionModel interventionModel;

    public InterventionModel getInterventionModel() {
        return interventionModel;
    }

    public void setInterventionModel(InterventionModel interventionModel) {
        this.interventionModel = interventionModel;
    }

    Object getImoProductLabel(){
        return interventionModel.imo_product_label();
    }
}

then in the template:

"label": "${intervention.imoProductLabel}"

this way, you will build the method not only for the template, but other places in code and abstract away your legacy code.