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
- does java have similar c# properties?
- (no) properties in java?
- http://blog.netopyr.com/2011/05/19/creating-javafx-properties/
- http://www.eclipse.org/forums/index.php/t/781816/
- why use getters , setters?
- what advantage of having private attribute getters , setters?
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.
a request extend lombok javafx properties exists here: https://groups.google.com/forum/#!searchin/project-lombok/getter$20and$20setter$20for$20properties/project-lombok/ik6phxdxhvu/zzdkc2mpmvgj
here intro on how extend lambok custom transformations: http://notatube.blogspot.de/2010/12/project-lombok-creating-custom.html
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 expectmyatom.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
Post a Comment