reflection - "Special attributes/properties" instead of getter/setter in Java to avoid boiler plate code -


intro

i working on open source project treez organize called "atoms" in tree view. atoms have a lot of attributes , attributes modified either through user actions in tree view or through api in eclipse code editor.

the attributes of atoms represented reusable "attributeatoms". hold actual attribute value , provide additional functionality validation (other possible terms "atom" might "widget", "bean", "property" or "tree node").

question(s)

in past provided getter/setter pair each of atom attributes. lot of work , blows size of atom classes (see code examples below). looking alternative solution that

  • makes less work create new atoms (and less work maintain them).
  • avoids "redundant" getter/setter boiler plate code.

i'm going describe few options below. of options use? have suggestions on how improve options? know further options?

getter/setter code example

    private attributeatom<string> myattribute = new filepathattributeatom("myattribtue");      public string getmyattribute() {         return myattribute.getvalue();     }          public void setmyattribute(string value) {         this.myatrribute.setvalue(value);     } 

related articles

considered options

a. auto generated getters/setters ide

eclipse provides possibility auto generate getters/setters.

  • does not work attributeatoms since gettter/setter code looks different.
  • does not avoid "redundant" code.

if decide keep getters/setters, try create similar attributeatoms. see post (not working) automatic getter/setter creation javafx properties: http://www.eclipse.org/forums/index.php/t/781816/

b. annotations generating getters/setters (project lombok)

lombok provides possibility use annotations automatic generation of getters , setters.

  • does neither work attributeatoms
  • i tried use lombok eclipse. code completion in editor worked got "method not found" warnings. might need invest more time lombok working classical attributes.
  • also see is safe use project lombok?

if decide use annotations define getters/setters, might possible extend lombok work attributeatoms.

c. 1 generalized getter/setter attributes

i use single getter/setter pair atom attributes

object get(string attributename) void set(string attriutename, object value) 
  • type safety improved passing additional type arguments.
  • however, code completion atom suggest single getter/setter , user not see attributes available. (maybe addressed using enums instead of strings identify attributes. enums need created somehow. see next option.)

d. custom eclipse editor , code processing

maybe write eclipse plugin open source project "allows access private attributes" suggesting corresponding fake methods code completion. before compiling user source code, fake calls like

myatom.setmyattribue(newvalue); 

would translated code existing generalized getter (option c):

myatom.set("myattribute", newvalue); 

e. public attributes

if make atom attributes public, not need getters/setter code in each atom. instead, reusable attributeatoms provide get/set methods. usage example this

myatom.myattribute.get(); myatom.myattribute.set(newvalue); 

instead of

myatom.getmyattribute(); myatom.setmyattribute(newvalue); 

some disadvantages:

  • users need used "unconventional approach". java users might expect setmyattribute(newvalue) , c# users might expect myatom.myattribute = newvalue.
  • it possible exchange whole attributeatom, do not want allow:

    myatom.myattribute = completelydifferentattribute 

any strategies improve this?

  • is there way allow access methods of attribute while not allowing exchange attribute itself? need new access modifier like

    private *publicmethodaccess* attributeatom<string> myattribute; 

atom code example

here example atom class. if scroll bottom find many lines of code consumed getters/setters. ugly, isn't it?

package org.treez.results.atom.probe;  import java.util.arraylist; import java.util.list;  import org.apache.log4j.logger; import org.eclipse.swt.graphics.image; import org.treez.core.atom.attribute.attributeroot; import org.treez.core.atom.attribute.modelpath; import org.treez.core.atom.attribute.modelpathselectiontype; import org.treez.core.atom.attribute.section; import org.treez.core.atom.attribute.base.attributeatom; import org.treez.core.atom.variablerange.variablerange; import org.treez.core.data.column.columntype; import org.treez.data.column.columns; import org.treez.data.output.outputatom; import org.treez.data.table.table; import org.treez.results.activator;  /**  * collects data sweep , puts in single (probe-) table. table can easier used produce plots  * distributed sweep results.  */ public class sweepprobe extends abstractprobe {      /**      * logger class      */     @suppresswarnings("unused")     private static logger syslog = logger.getlogger(sweepprobe.class);      //#region attributes      private attributeatom<string> xlabel;      private modelpath xrange;      private attributeatom<string> ylabel;      private attributeatom<string> firstfamilylabel;      private modelpath firstfamilyrange;      private attributeatom<string> secondfamilylabel;      private modelpath secondfamilyrange;      private attributeatom<string> probename;      private modelpath sweepoutputmodel;      private modelpath firstprobetable;      private attributeatom<string> probecolumnindex;      private attributeatom<string> proberowindex;      //#end region      //#region constructors      /**      * constructor      *      * @param name      */     public sweepprobe(string name) {         super(name);         createpropertymodel();     }      //#end region      //#region methods      /**      * creates model property control      */     private void createpropertymodel() {          //root         attributeroot root = new attributeroot("root");          //page         org.treez.core.atom.attribute.page page = root.createpage("page");          //x section         section xsection = page.createsection("xsection", "x");         xsection.createsectionaction("action", "run probe", () -> execute(treeviewrefreshable));          xlabel = xsection.createtextfield("xlabel", "label x-axis", "x");          xrange = xsection.createmodelpath("xrange", "range x-axis", "", variablerange.class, this);         xrange.setselectiontype(modelpathselectiontype.flat);         xrange.setvalue("root.studies.sweep.threshold");          //y section         section ysection = page.createsection("ysection", "y");         ylabel = ysection.createtextfield("ylabel", "label y-axis", "y");          //first family section         section firstfamilysection = page.createsection("firstfamily", "first family");         firstfamilysection.setexpanded(false);          firstfamilylabel = firstfamilysection.createtextfield("firstfamilylabel", "label first family", "family1");          firstfamilyrange = firstfamilysection.createmodelpath("firstfamilyrange", "range first family", "",                 variablerange.class, this);          //second family section         section secondfamilysection = page.createsection("secondfamily", "second family");         secondfamilysection.setexpanded(false);          secondfamilylabel = secondfamilysection.createtextfield("secondfamilylabel", "label second family",                 "family2");          secondfamilyrange = secondfamilysection.createmodelpath("secondfamilyrange", "range second family", "",                 variablerange.class, this);          //probe section         section probesection = page.createsection("probe", "probe");          probename = probesection.createtextfield("propename", "name", "myprobe");          sweepoutputmodel = probesection.createmodelpath("sweepoutput", "sweepoutput", "", outputatom.class, this);          firstprobetable = probesection.createmodelpath("tablepath", sweepoutputmodel, table.class);         firstprobetable.setlabel("first probe table");          probecolumnindex = probesection.createtextfield("probecolumnindex", "column index", "0");          proberowindex = probesection.createtextfield("probecolumnindex", "row index", "0");          setmodel(root);      }      /**      * provides image represent atom      */     @override     public image providebaseimage() {         image baseimage = activator.getimage("sweep.png");         return baseimage;     }      //#region create table columns      /**      * creates required columns given table      *      * @param table      */     @override     protected void createtablecolumns(table table) {         //todo      }      //#end region      //#region collect probe data      @override     protected void collectprobedataandfilltable() {         // todo auto-generated method stub      }      //#end region      //#end region      //#region accessors      //#region x label      /**      * @return      */     public string getxlabel() {         return xlabel.getvalue();     }      /**      * @param label      */     public void setxlabel(string label) {         xlabel.setvalue(label);     }      //#end region      //#region x range      /**      * @return      */     public string getxrange() {         return xrange.getvalue();     }      /**      * @param range      */     public void setxrange(string range) {         xrange.setvalue(range);     }      //#end region      //#region y label      /**      * @return      */     public string getylabel() {         return ylabel.getvalue();     }      /**      * @param label      */     public void setylabel(string label) {         ylabel.setvalue(label);     }      //#end region      //#region first family label      /**      * @return      */     public string getfirstfamilylabel() {         return firstfamilylabel.getvalue();     }      /**      * @param label      */     public void setfirstfamilylabel(string label) {         firstfamilylabel.setvalue(label);     }      //#end region      //#region first family range      /**      * @return      */     public string getfirstfamilyrange() {         return firstfamilyrange.getvalue();     }      /**      * @param range      */     public void setfirstfamilyrange(string range) {         firstfamilyrange.setvalue(range);     }      //#end region      //#region second family label      /**      * @return      */     public string getsecondfamilylabel() {         return secondfamilylabel.getvalue();     }      /**      * @param label      */     public void setsecondfamilylabel(string label) {         secondfamilylabel.setvalue(label);     }      //#end region      //#region second  family range      /**      * @return      */     public string getsecondfamilyrange() {         return secondfamilyrange.getvalue();     }      /**      * @param range      */     public void setsecondfamilyrange(string range) {         secondfamilyrange.setvalue(range);     }      //#end region      //#region probe      /**      * @return      */     public string getprobename() {         return probename.getvalue();     }      /**      * @param name      */     public void setprobename(string name) {         probename.setvalue(name);     }      //#end region      //#region sweep output model      /**      * @return      */     public string getsweepoutputmodelname() {         return sweepoutputmodel.getvalue();     }      /**      * @param sweepoutputmodel      */     public void setsweepoutputmodelname(string sweepoutputmodel) {         this.sweepoutputmodel.setvalue(sweepoutputmodel);     }      //#end region      //#region probe table      /**      * @return      */     public string getfirstprobetable() {         return firstprobetable.getvalue();     }      /**      * @param firstprobetable      */     public void setfirstprobetable(string firstprobetable) {         this.firstprobetable.setvalue(firstprobetable);     }      //#end region      //#region column index      /**      * @return      */     public string getprobecolumnindex() {         return probecolumnindex.getvalue();     }      /**      * @param index      */     public void setprobecolumnindex(string index) {         probecolumnindex.setvalue(index);     }      //#end region      //#region row index      /**      * @return      */     public string getproberowindex() {         return proberowindex.getvalue();     }      /**      * @param index      */     public void setproberowindex(string index) {         proberowindex.setvalue(index);     }      //#end region      //#end region  } 

for option e, using "final" modifier prevent whole new attributeatom being swapped in, whilst still allowing getting/setting:

public final attributeatom<string> myattribute = new filepathattributeatom("myattribtue"); 

then following allowed:

myatom.myattribute.get(); myatom.myattribute.set(newvalue) 

but thing you're worried won't be:

myatom.myattribute = completelydifferentattribute 

Comments