In a Struts 2 class where http get params are auto fetched by field variables. While there were repeated such class fields like userId,groupId, etc in many classes, I decided to make one business object class RequestParams in each class and put all the field there.
Then all my class will have just the RequestParams rp; with getRp(); and setRp(); the rp class will have the userId with getters / setters and all other fields.
Now I see I have to replace. e.g userId with getRp().getUserId(); at line 34 Now the code is looking ugly.
With this: messageId = ChatDao.saveMessage(userId,groupId , message);
would look like
rp.setMessageId( ChatDao.saveMessage(rp.getUserId(), rp.getGroupId(), rp.getMessag() ) );
what is a better way of doing such things?
public class SendMessageOrStartChatAction extends BaseActoinSupport{
private static final long serialVersionUID = 1L;
private int userId;
private int groupType;
private int groupId;
private String groupTitle;
private String groupMemberIds;
private int randomCode;
private String message;
private int messageId; //internal class ues
#Override
/** boo */
protected void doExecute() throws IOException {
//check if it had random code in db, (msg already saved in db)
if(ChatDao.randomCodeExists(randomCode)){
messageId = ChatDao.getMessageIdThatMatchesRandomCode(randomCode);
write(messageId);
}else{
if(groupId <= 0){
//create group
groupId = ChatDao.createChatGroup(userId, groupTitle, groupType);
String[] memberIdsArray = groupMemberIds.split("==");
ChatDao.addUsersToGroup(groupId, memberIdsArray);
}
//save message
messageId = ChatDao.saveMessage(userId,groupId , message);
// queued: may be put this in last viewed messages here. may be.
write(messageId);
}
}
}
Nothing wrong with this approach, if you aggregate a class and want to access its properties then public accessors are appropriate to you and you could also access them via OGNL. The action is on top of the valueStack, so expression will look much simpler "rp.userId" for example. Anyway there's no need to pass all params to the method, you can use a simplified method signature
ChatDao.saveMessage(rp);
and inside the method access those parameters.
Related
I am writing a RequestBuilder class, which will handle the creation of a query string, based on the following criteria
category (String)
country (String)
keywords (String[])
page (int)
pageSize (int)
Since not all criteria are mandatory and there are many combinations between them (I counted 7, of which only four should be valid - see below why), I decided to use the builder pattern:
public class RequestBuilder {
private String category = "";
private String country = "&country=us";
private String keywords = "";
private String page = "";
private String pageSize = "&pageSize=100";
public RequestBuilder() {
}
private String buildQuery() {
return this.category + this.country + this.keywords + this.page + this.pageSize;
}
// the setter methods, which I omitted for readability
But there is a problem. I need to force the user to specify at least two of either category, country or keywords before building the object(right now the user isn't obliged to specify even one!). A user shouldn't be able to create an object by specifying only country, for example.
So how do I force this requirement? If I make three constructors(each having two of those parameters) I feel like I am ruining the Builder pattern, even though there will be three more optional properties to specify.
As a designer, you need to decide what fields are really required. There is no such thing as "maybe required". To use Builder Pattern and enforce required parameters, mark the fields as final and inject them through the constructor:
public class Request {
// fields
private final String requiredField;
private final String optional1;
private final String optional2;
private Request(RequestBuilder builder) {
requiredField = builder.requiredField;
optional1 = builder.optional1;
optional2 = builder.optional2;
}
// add only getter method to the Request class (builds immutable Request objects)
public static class RequestBuilder {
private final String requiredField;
private String optional1;
private String optional2;
public RequestBuilder(String requiredField) {
this.requiredField = requiredField;
}
public RequestBuilder setOptional1(String optional1) {
this.optional1 = optional1;
return this;
}
public RequestBuilder setOptional2(String optional2) {
this.optional2 = optional2;
return this;
}
public Request build() {
return new Request(this);
}
}
}
The builder enforces required and optional fields. The object being built by the builder hides the constructor so that it is only accessible via the builder. The fields inside the request object are all final for immutability.
To use, you'll do something like this:
RequestBuilder builder = new RequestBuilder("required");
Request request = builder.setOptional1("foo").setOptional2("bar").build();
or you could simply call build() at any time after calling the builder constructor.
UPDATE:
Now to your problem.... You could (potentially) modify the build() to check how many "semi-required" fields you have with values and compare it to the total number of fields. To me, this is a hack. For this, you have two options
Hard code the number of fields and check how many out of the total number are still null or empty. If the number of fields that are not set is below a certain count, throw some exception (i.e. InvalidRequiredFieldCount). Otherwise, you return the new instance. For this, you need to increment the "count" every time a setter method is called.
Use reflection to get the list (array) of fields and use this field and use this field count to calculate the minimum number of "required" fields. Throw exception if that minimum is not reach or return a new request instance if the minimum threshold is reached.
public Request build() throws Exception {
Request request = new Request(this);
int count = 0;
int max = 2;
Field[] allFields = Request.class.getDeclaredFields();
for (Field field : allFields) {
Object o = field.get(request);
if (o != null) {
count++;
}
}
if (count < 2) {
throw new Exception("Minimum number of set fields (2) not reached");
}
return request;
}
This is not pretty, but it works. If I run this:
RequestBuilder builder = new RequestBuilder("required");
Request request = builder.build();
will result in an exception:
Exception in thread "main" java.lang.Exception: Minimum number of set fields (2) not reached
at com.master.oxy.Request$RequestBuilder.build(Request.java:54)
at com.master.oxy.Request.main(Request.java:63)
However, if I set at least one optional, the new instance will be returned.
I would like to suggest another object-oriented solution for that problem:
Let's assume you don't want to pass the required arguments to the builder c'tor. You can use the following technique to enforce providing the required field during the build process of the object:
Usage - demonstrate how only the required field is visible first:
Usage2 - demonstrate how the rest of the optional and build() methods are visible after providing the required field:
We implement it by doing the following:
public static class RequestBuilder implements RequestBuilderRequiredField {
public interface RequestBuilderRequiredField {
RequestBuilder setRequiredField(String requiredField)
}
private final String requiredField;
private String optional1;
private String optional2;
private RequestBuilder() {
}
public static RequestBuilderRequiredField aRequestBuilder() {
return new RequestBuilder();
}
Note the the builder c'tor is private because we want to expose first the interface with the required field (and if have many, we want to chain the interfaces methods so they will return an interface for for each required field)
The downside of that approach is that you need to maintain the same amount of interfaces on a large object when many (or even all) properties are required.
Interesting to think if libraries such as Lombok that auto generates Builder with #Builde annotation can have the ability to generate it
I'm not looking for the best way to do this, but rather for any way to do what i need while adhering to the DRY principle.
Let's say I have a class Source as follows. Source contains thirty strings.
class Source {
private String sourceAttrOne = "sourceValueOne";
private String sourceAttrTwo = "sourceValueTwo";
...
private String sourceAttrThirty = "sourceValueThirty";
}
This information is to be used to create a new object of class Destination. 25 of Destination's attributes have a name in a similar format (but not the same name). 10 of these are Strings, while 5 are Dates, and 5 are Integers. The last 5 fields, however, are totally different.
class Destination {
private String AttrOne;
...
private Date AttrSixteen;
...
private Integer AttrTwentyOne;
...
// Last 5 fields are different
private SomeOtherClass someOtherName;
private TheBestClass imAlsoSpecial;
// Standard getters and setters
}
For the 25 "normal" attributes, I need to use a helper method to get from the source value to the result. The helper method used depends on the destination type:
destination.setAttrOne(getResultingString(source.getSourceAttrOne()));
destination.setAttrSixteen(getResultingDate(source.getSourceAttrSixteen());
destination.setAttrSeventeen(getResultingDate(source.getSourceAttrSeventeen()/*, custom Date format for AttrSeventeen */));
The remaining 5 attributes need custom (individual) logic.
Any pointers in the right direction would be much appreciated, I don't need a complete solution :)
N.B.: I'm probably totally mistaken, so nevermind me if that's the case.
I also haven't unlocked comments yet, while it would be more likely the best; sorry for the inconvenience.
If the 1st to 15th attributes are String, then supposedly, you can simply affect them to the corresponding attributes, or clone them first, if you prefer.
For the 16th to 21th(?), which are dates, you might be able to use DateFormat's parse(String) method; although, I'm clueless on how to help the compiler to get the used format or if it can do it properly by itself.
For the 22th to 27th(?), the Integers, you should be able to use Integer's parse(String) method, or possibly through Double's and then convert back to an Integer or an int.
You can try Reflection for similar targets.
Something like:
public void fillFieldsHelper(Object source) {
List<Field> sourceFields = source.getClass().getDeclaredFields();
or
Field valueOne = source.getClass().getDeclaredField("sourceAttrOne");
System.out.println(valueOne.getName());
System.out.println(valueOne.getType());
...
Object value = valueOne.get(source);
Field attrOne = this.getClass().getDeclaredField(valueOne.getName().replace("source",""));
switch (attrOne.getType().getName()) {
case "java.lang.Integer":
attrOne.set(this, Integer.valueOf(value));
break;
default:
attrOne.set(this, value);
}
...
etc.
I can't say that Reflection is elegant but it's useful in many cases.
So in your case you have several possibilities.
Create Object from Object
The easiest but maybe not the nicest solution (depending on your further process/requirements) is to have a constructer which has the need Object as parameter.
public class Source {
private String sourceAttrOne;
private String sourceAttrTwo;
// further class attributes....
// getters (& setters)
}
public class Destination {
private String attrOne;
private String attTwo;
public Destination(Source source) {
this.attrOne = source.getSourceAttrOne;
this.attrTwo = source.getSourceAttrTwo;
// etc..
}
}
User Builder Pattern
The problem in the solution above is, that depending of which fields are required for creating the Destination.class the constructer is going to have a lot of parameters. In addition, if you have to change your constructer in the future (e.g. additional required fields), you have to create a new constructer or change the already existing one (which implies you have to change all the current usages of that).
Therefore to hold the DRY, I would recommend the Builder Patter.
public class Destination {
private String attrOne;
private String attTwo;
private String attThree; // attribute which comes not from any other source class and is e.g. not a required field
private Destination() {
// should not be accessible
}
public static class Builder {
private String attrOne;
private String attTwo;
private String attThree;
private Builder() {
// do nothing
}
public static Builder create(Source source) {
Builder builder = new Builder();
builder.attrOne = source.getSourceAttrOne();
builder.attrTwo = source.getSourceAttrTwo();
return builder;
}
public Builder attThree(String attThree) {
this.attThree = attThree;
return this;
}
public Destination build() {
Destination destination = new Destination();
destination.attrOne = builder.attrOne;
destination.attrTwo = builder.attrTwo;
destination.attrThree = builder.attrThree;
//add several validations e.g. assert destination.attrOne != null
return destination;
}
}
}
To create a Destination.class with Source.class you can do following:
Destination.Builder.create(source).build();
For having different Types e.g. Source.sourceAttrOne is a String and the in the Destination.attrOne is a Date, you just have to adjust the Destination.class.
public class Destination {
private LocalDate attrOne;
// ...
private Destination() {}
public static class Builder {
private String attrOne;
// ...
private Builder() {}
public static Builder create(Source source) {
Builder builder = new Builder();
builder.attrOne = LocalDate.parse(source.getSourceAttrOne());
// ...
return builder;
}
public Destination build() {
Destination destination = new Destination();
destination.attrOne = builder.attrOne;
// ...
return destination;
}
}
}
I have multiple methods in a Java class where every method has 20+ parameters. I will create an object for this class in another class and call each and every method. Typically I'm using the POM (Page Object Model) in Selenium Java.
So in every Page object class, there are multiple(20+) parameters in every method, which I will call in the Test Class.
Page Object Class :
public void enterShipInfo(String IMO,String Vstat,String Vcode,String Vname,
String Vtype,String Officialno,String Buildyr,String Shipyard,String Hullno,String Layingdate,
String Launcheddate,String Deliverdate,String Reportinclude,String Portregistry,String VFlag,
String Vstatus,String Classification,String Classid,String Classnotation,String PI,String HM,
String Regowner,String Shipmanager,String Comoperator,String Callsign,String SSR,String Factor,
String ELOG,String Vcomments,String VsisIMO,String Chartertype,String Showonweb){
}
.... Other Methods with similar long list of parameters
Then in Test Class, again I'm creating parameters for these:
public class VesTest {
#Test(dataProvider="Ves",priority=1)
public void createVesTest(String IMO,String Vstat,String Vcode,String Vname,
String Vtype,String Officialno,String Buildyr,String Shipyard,String Hullno,String Layingdate,
String Launcheddate,String Deliverdate,String Reportinclude,String Portregistry,String VFlag,
String Vstatus,String Classification,String Classid,String Classnotation,String PI,String HM,
String Regowner,String Shipmanager,String Comoperator,String Callsign,String SSR,String Factor,
String ELOG,String Vcomments,String VsisIMO,String Chartertype,String Showonweb
Mdr_Vessel obj_Mdr_Vessel = page(Mdr_Vessel.class);
obj_Mdr_Vessel.clickSubmenu();
.....
}
Any efficient way to reduce typing the parameters again in Test Class???
I don't want to break the method into multiple methods. So please suggest me a way of passing parameters in an efficient way
You can create new objects to group your parameters and then use them in your method signature.
For example :
public class VParameter {
String Vstat;
String Vcode;
String Vname;
String Vtyp;
I don't know if this counts as "breaking up the method into multiple methods", but what you can do is collect the parameters in a single object. Then for example
void method(Type1 parameter1, Type2 parameter2, Type3 parameter3) { ... }
becomes:
public class Parameters {
private Type1 parameter1;
private Type2 parameter2;
private Type3 parameter3;
// getters and setters
}
void method(Parameters params) { ... }
This kind of pattern is often used in a fluent style:
public class Parameters {
private Type1 parameter1 = /* convenient default value */;
private Type2 parameter2 = /* convenient default value */;
private Type3 parameter3 = /* convenient default value */;
public Parameters setParameter1(Type1 parameter1) {
this.parameter1 = parameter1;
return this;
}
// other setters in the same style and getters
}
Then you can call your method like:
method(new Parameters().setParameter1(...).setParameter3(...));
(where you only set the parameters with non-default values).
Can you create a class to regroup all parameters ?
You should read about the Prameter object patter which deals with that type of problem. In brief, it suggests you to crate a wrapper object for all parameters that the method accepts and use it instead the long list of arguments.
public class YourClassName {
private String IMO;
private String Vstat;
private String Vcode;
// other parameters
public YourClassName(String IMO, String Vstat, String Vcode, /* other params*/) {
this.IMO = IMO;
this.Vstat = Vstat;
this.Vcode = Vcode;
// assign other params
}
/getters
}
You can use the builder factory pattern https://jlordiales.wordpress.com/2012/12/13/the-builder-pattern-in-practice/
I'm just starting my first steps with Java, learned all the basics but then found a problem with an enum I need, so forgive me, if the solution to my problem is something very obvious:
So I've got this enum and want to add a unique id to each instance counting from 0 upwards, but without having to add another parameter to each constructor calling (because this can later on lead to errors ofc).
public enum TerrainTile{
WATER(1), GRASSLAND(1), HILL(2), FORREST(2), BLANK(99);
private final int id;
private final int moveCost;
private boolean hidden = true;
private TerrainTile(int moveCost) {
this.moveCost = moveCost;
}
And I thought to just add a
static int nextID = 0;
and edit the constructor to
private TerrainTile(int moveCost) {
this.id = nextID++;
this.moveCost = moveCost;
}
But I get an error message that it can not refer to a static field inside the initializer.
Is there any workaround?
You can use the ordinal() method for it. It is based on the order in which the members are declared in the source-code and counted from zero. So I guess, exactly what you need.
Just a note:
You can get your original enum member from ordinal number by calling .values()[index]
example:
int hillOrdinal = TerrainTile.HILL.ordinal(); // 2
TerrainTile hill = TerrainTile.values()[hillOrdinal];
It sounds like you are trying to combine class features into an enum. I'd be particularly wary of non-final, non-static member fields in an enum declaration. The behaviour you want seems to be best served by using a TerrainTile class (possibly a flyweight if you truly want the single-instance-per-type behaviour) and a TerrainTileType (or TerrainTile.Type) enum. Something like this:
public class TerrainTile {
public enum Type {
WATER(1), GRASSLAND(1), HILL(2), FORREST(2), BLANK(-1);
public final int MOVE_COST;
private TerrainTile(int moveCost) {
this.MOVE_COST = moveCost;
}
public boolean isTraversable() {
return (MOVE_COST > 0);
}
}
private final Type type;
private final Image texture;
...
private TerrainTile(Type type) {
this.type = type;
}
private static final Map<Type, TerrainTile> tiles = new EnumMap<>();
static {
// instantiate one TerrainTile for each type and store into the tiles Map
for (Type type: Type.values()) {
// Eventually, also load tile textures or set Color in this step
tiles.put(type, new TerrainTile(type));
}
}
public static TerrainTile getTile(Type type) {
// return the reference to the TerrainTile of this type
return tiles.get(type);
}
...
}
Im implementing some generic components and I just wonder if my design patters makes sense and if there are any improvements that can be made. E.g., here is a generic panel that can be used to filter stuff:
/**
* Abstract class for textfields used for filtering. When overriding abstract method onUpdateFilter, the first thing
* that must be done is to set the paramsobject, or else filtering wont work.
* #author fred
*
*/
public abstract class FilterFormPanel extends Panel {
private static final long serialVersionUID = 1L;
private FilterForm filterForm;
private Object paramsObject; //this is object because paramsobjects differ depending on entity type
public FilterFormPanel(String id) {
super(id);
filterForm = new FilterForm("filterForm");
add(filterForm);
}
public String getFilterString(){
return filterForm.getFilterString();
}
public void setParamsObject(Object paramsObject){
this.paramsObject = paramsObject;
}
/**
*For developers to implement in class that contains the correct references to params and facade objects, dataviews etc.
*e.g. they could do params.setFilter(<reference to an instance of this class>.getFilterString() and ajax stuff too)
*/
public abstract void onUpdateFilter(AjaxRequestTarget target, Object paramsObject);
private class FilterForm extends Form<Void> {
private static final long serialVersionUID = 1L;
private transient String filterString;
public FilterForm(String id) {
super(id);
final TextField<String> filterTextField = new TextField<String>("filterTextField", new PropertyModel<String>(this, "filterString")); //textField for user to enter filter string
add(filterTextField);
add(new AjaxButton("filterButton") { //button to click for performing overriden method
private static final long serialVersionUID = 1L;
#Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
onUpdateFilter(target, paramsObject);
}
});
}
public String getFilterString(){
return filterString;
}
}
}
Used as follows in another class:
filterFormPanel = new FilterFormPanel("filterFormPanel"){
private static final long serialVersionUID = 1L;
#Override
public void onUpdateFilter(AjaxRequestTarget target, Object paramsObject) {
filterFormPanel.setParamsObject(params);
params.setFilterString(filterFormPanel.getFilterString());
//ajax stuff
target.addComponent(dataViewContainer);
nav.setVisible(dataProvider.size()!=0);
target.addComponent(nav);
emptyLabel.setVisible(dataProvider.size()==0);
target.addComponent(emptyLabel);
}
};
settingsContainer.add(filterFormPanel);
Its kind of annoying that one is forced to use the setParamsObject method first thing when one overrides the method. Is there a nicer way of achieving a reference to that object? And is this is general a sane way of implementing reusable and relatively generic components in wicket? Any feedback would be greatly appreciated, Im sure theres room for improvement here.
EDIT I: Just for some context, what Im doing is Im implementing pages like these
where I present the user with a dataview and options for filtering it. There are lots of pages for lots of different entities, but the GUI components can and should be made as generic as possible as to not violate DRY. The example code is obviously the filter textfield and button part of the page.
EDIT II: I want this component to be even more loosely coupled if possible, e.g. make it able to do completely different things, not just modifying a params object (say, e.g. have another case where I need to update TWO params objects, then I wont be able to use this panel). The onSubmit method in the form as it is now requires a reference to the objects to be used in the overriden method are known beforehand. Is there any way to not have it that way or set the presence and/or types of those objects dynamically?
EDIT III: The point is that this panels core function really is only to allow the user to
enter a string
notify and give access to that string to some other part of the system when the user clicks the button.
What that "other part of the system" does with the string should not really have to concern this panel, but as it is now, it is coupled to the params object upon which "the other part of the system" must perform some operation. It is this coupling I would like to get rid of if possible. I might as well want to use the string from this panel for just printing to console or use it for some other arbitrary task.
You can use the constructor of the class to set the object.
A more generic approach would be if you let paramsObject make use of the Java Generics (hence the name :)). You could superclass the entities or let them implement an interface.
I work for more than 3 years on a web application using Wicket (started using 1.3.x now under 1.4.x and planning to upgrade to 1.5.x in a few weeks). The approach you are using is the one we use internally. We often use abstract classes to represents common panels. The only thing we do is what rotsch said in his answer, we use a lot of generics to infer the type arguments as much as possible.
Actually, even though I didnt realize it at first, this could be achieved quite easily with by simply doing this:
/**
* Abstract class for textfields used for filtering.
* #author fred
*
*/
public abstract class FilterStringPanel extends Panel {
private static final long serialVersionUID = 1L;
private FilterForm filterForm;
public FilterStringPanel(String id) {
super(id);
filterForm = new FilterForm("filterForm");
add(filterForm);
}
public String getFilterString(){
return filterForm.getFilterString();
}
/**
*For developers to implement in class that contains the correct references to params and facade objects, dataviews etc.
*e.g. they could do params.setFilter(<reference to an instance of this class>.getFilterString() and ajax stuff too)
*/
public abstract void onUpdateFilter(AjaxRequestTarget target);
private class FilterForm extends Form<Void> {
private static final long serialVersionUID = 1L;
private transient String filterString;
public FilterForm(String id) {
super(id);
final TextField<String> filterTextField = new TextField<String>("filterTextField", new PropertyModel<String>(this, "filterString")); //textField for user to enter filter string
add(filterTextField);
add(new AjaxButton("filterButton") { //button to click for performing overriden method
private static final long serialVersionUID = 1L;
#Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
onUpdateFilter(target);
}
});
}
public String getFilterString(){
return filterString;
}
}
}
And then implementing it this way:
settingsContainer.add(new FilterStringPanel("filterStringPanel"){
private static final long serialVersionUID = 1L;
#Override
public void onUpdateFilter(AjaxRequestTarget target) {
params.setFilterString(getFilterString());
target.addComponent(dataViewContainer);
nav.setVisible(dataProvider.size()!=0);
target.addComponent(nav);
emptyLabel.setVisible(dataProvider.size()==0);
target.addComponent(emptyLabel);
}
});
This way we dont need to send any references to any objects (e.g. params objects or wicket components that needs to be targeted for updating with AJAX) and we can re-use this panel for whatever we want!