Builder pattern that requires at least two properties to be specified - java

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

Related

How to map class fields to another class?

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;
}
}
}

How to validate each process object from its own validator?

I have two process and for each process, I will get different Record object and I need to validate those Record object. This means I cannot use single validator as I have to validate different fields for both the process.
For processA, I am using ValidatorA class to validate its Record object.
For processB, I am using ValidatorB class to validate its Record object.
If they are valid, then I will move forward otherwise I won't move forward. Below is my process code both for A and B.
public class ProcessConsumer implements Runnable {
private static final Logger logger = Logger.getInstance(ProcessConsumer.class);
private final String processName;
private final Validator validator;
private final RecordProcessor<byte[], byte[]> process;
public ProcessConsumer(String processName, Validator validator) {
this.processName = processName;
this.validator = validator;
this.process = new RecordProcessor<>();
}
#Override
public void run() {
try {
process.subscribe(getTopicsBasedOnProcessName(processName));
....
while (true) {
ConsumerRecords<byte[], byte[]> crs = process.poll(2000);
for (ConsumerRecord<byte[], byte[]> cr : crs) {
// record object will be different for my both the processes.
Record record = decoder.decode(cr.value());
Optional<DataHolder> validatedHolder = validator.getDataHolder(processName, record);
if (!validatedHolder.isPresent()) {
logger.logError("records dropped. payload= ", record);
continue;
}
// send validatedHolder to processor class
Processor.getInstance().execute(validatedHolder);
}
}
} catch (Exception ex) {
logger.logError("error= ", ExceptionUtils.getStackTrace(ex));
}
}
}
Below is my ValidatorA class in which I am validating few fields on record object and if it is valid, then I am returning DataHolder.
public class ValidatorA extends Validator {
private static final Logger logger = Logger.getInstance(ValidatorA.class);
#Override
public static Optional<DataHolder> getDataHolder(String processName, Record record) {
Optional<DataHolder> dataHolder = Optional.absent();
if (isValid(processName, record))
dataHolder = Optional.of(buildDataHolder(processName, record));
return dataHolder;
}
private DataHolder isValid(String processName, Record record) {
return isValidClientIdDeviceId(processName, record) && isValidPayId(processName, record)
&& isValidHolder(processName, record)
}
private DataHolder buildDataHolder(String processName, Record record) {
Map<String, String> holder = (Map<String, String>) DataUtils.extract(record, "holder");
String deviceId = (String) DataUtils.extract(record, "deviceId");
Integer payId = (Integer) DataUtils.extract(record, "payId");
String clientId = (String) DataUtils.extract(record, "clientId");
// add mandatory fields in the holder map after getting other fields
holder.put("isClientId", (clientId == null) ? "false" : "true");
holder.put("isDeviceId", (clientId == null) ? "true" : "false");
holder.put("abc", (clientId == null) ? deviceId : clientId);
return new DataHolder.Builder(record).setClientId(clientId).setDeviceId(deviceId)
.setPayId(String.valueOf(payId)).setHolder(holder).build();
}
private boolean isValidHolder(String processName, Record record) {
Map<String, String> holder = (Map<String, String>) DataUtils.extract(record, "holder");
if (MapUtils.isEmpty(holder)) {
logger.logError("invalid holder is coming.");
return false;
}
return true;
}
private boolean isValidpayId(String processName, Record record) {
Integer payId = (Integer) DataUtils.extract(record, "payId");
if (payId == null) {
logger.logError("invalid payId is coming.");
return false;
}
return true;
}
private boolean isValidClientIdDeviceId(String processName, Record record) {
String deviceId = (String) DataUtils.extract(record, "deviceId");
String clientId = (String) DataUtils.extract(record, "clientId");
if (Strings.isNullOrEmpty(clientId) && Strings.isNullOrEmpty(deviceId)) {
logger.logError("invalid clientId and deviceId is coming.");
return false;
}
return true;
}
}
And below is my ValidatorB class in which I am validating few different fields as compared to ValidatorA on record object and if it is valid, then I am returning DataHolder.
public class ValidatorB extends Validator {
private static final Logger logger = Logger.getInstance(ValidatorB.class);
#Override
public static Optional<DataHolder> getDataHolder(String processName, Record record) {
Optional<DataHolder> dataHolder = Optional.absent();
if (isValid(processName, record))
dataHolder = Optional.of(buildDataHolder(processName, record));
return dataHolder;
}
private DataHolder isValid(String processName, Record record) {
return isValidType(processName, record) && isValidDatumId(processName, record) && isValidItemId(processName, record);
}
private DataHolder buildDataHolder(String processName, Record record) {
String type = (String) DataUtils.extract(record, "type");
String datumId = (String) DataUtils.extract(record, "datumId");
String itemId = (String) DataUtils.extract(record, "itemId");
return new DataHolder.Builder(record).setType(type).setDatumId(datumId)
.setItemId(itemId).build();
}
private boolean isValidType(String processName, Record record) {
String type = (String) DataUtils.extract(record, "type");
if (Strings.isNullOrEmpty(type)) {
logger.logError("invalid type is coming.");
return false;
}
return true;
}
private boolean isValidDatumId(String processName, Record record) {
String datumId = (String) DataUtils.extract(record, "datumId");
if (Strings.isNullOrEmpty(datumId)) {
logger.logError("invalid datumId is coming.");
return false;
}
return true;
}
private boolean isValidItemId(String processName, Record record) {
String itemId = (String) DataUtils.extract(record, "itemId");
if (Strings.isNullOrEmpty(itemId)) {
logger.logError("invalid itemId is coming.");
return false;
}
return true;
}
}
And below is my abstract class:
public abstract class Validator {
public abstract Optional<DataHolder> getDataHolder(String processName, Record record);
}
Question:
This is how I am calling for both of my process. As you can see, I am passing processName and its particular validator in the constructor argumnets.
ProcessConsumer processA = new ProcessConsumer("processA", new ValidatorA());
ProcessConsumer processB = new ProcessConsumer("processB", new ValidatorB());
Is this a good design where for each of my process, pass its validator along with?
Is there any way we can avoid passing that? And internally figure out what validators to use basis on the processName? I already have an enum with all my processName. I need to make this design extensible so that if I add new process in future, it should be scalable.
Also the way I have my abstract class Validator is right? It is not doing any useful things at all looks like.
Each of my Validator is basically trying to validate whether the record object is valid or not. If they are valid, then they make DataHolder builder and return it, otherwise it returns Optional.absent();
I saw this post where they talked about using Decorator pattern but I am not sure how that will help me in this case.
First when I see the declaration and the implementation of them :
public abstract class Validator {
public abstract Optional<DataHolder> getDataHolder(String processName, Record record);
}
I don't think "Validator" is the best term. Your validators are not only validators. What you call validators have as main function : extract data for a specific process. The extraction requires a validation but it is not the main function.
While the main function of a validator is validating.
So I think you could call them something as : ProcessDataExtractor.
ProcessConsumer processA = new ProcessConsumer("processA", new ValidatorA());
ProcessConsumer processB = new ProcessConsumer("processB", new ValidatorB());
Is this a good design where for each of my process, pass its validator
along with? Is there any way we can avoid passing that? And internally
figure out what validators to use basis on the processName? I already
have an enum with all my processName. I need to make this design
extensible so that if I add new process in future, it should be
scalable.
Scalability is another thing.
Having a extensible design is broadly having a design which doesn't imply important and or risky modifications as soon as a new "normal" requirement happens in the life of the application.
If a new process consumer is added, you have to add a ProcessDataExtractor according to your needs. The client should be aware of this new process consumer.
If the client code instantiate its process consumer and its data extractor at compile-time, using enum and map to represent process consumers and data extractors doesn't make your design not expandable since it requires very little of modification and these are isolated
If you want to have still less of modification in your code, you could instantiate by reflection the extractor and using a naming convention to retrieve them. For example, place them always in the same package and name each extractor with the same prefix, for example : ProcessDataExtractorXXX or XXX is the variable part.
The problem of this solution is at compile time : clients doesn't know necessary the ProcessDataExtractor available.
If you want that the adding of a new process consumer and extractor to be dynamic, that is during the runtime of the application and that clients may retrieve them during runtime too, it is another subject I think.
At compile-time, the design could be better because so far the client of the ProcessConsumer and ProcessDataExtractor classes may make a bad use of them (that is using Process A with ProcessDataExtractor B).
To avoid that, you have several ways of doing.
But you have guessed the idea : making the initialization and the mapping between ProcessConsumer and ProcessDataExtractor in a dedicated place and a protected way.
To achieve it, I advise you to introduce a interface for ProcessConsumer which provides only the functional method from Runnable:
public interface IProcessConsumer extends Runnable {
}
From now clients who want to consume a process should only use this interface to perform their task. We don't want provide to the client method or constructor to choose its data extractor.
To do it, the concrete ProcessConsumer class should be an inner private class in order to not allow clients to instantiate it directly.
They will have to use a factory to address this need.
In this way, client are able to create the specific process consumer with the required data extractor by requesting a factory of Processes which is responsible to ensure the consistence between a data extractor and a process and which also guarantees the instantiation of a new process consumer at each call (your processes are stateful, so you have to create a new process consumer for each process consumer you start).
Here is the ProcessConsumerFactory class :
import java.util.HashMap;
import java.util.Map;
public class ProcessConsumerFactory {
public static enum ProcessType {
A("processA"), B("processB");
private String name;
ProcessType(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
private class ProcessConsumer implements IProcessConsumer {
private final ProcessType processType;
private final ProcessDataExtractor extractor;
private final RecordProcessor<byte[], byte[]> process;
public ProcessConsumer(ProcessType processType, ProcessDataExtractor extractor) {
this.processType = processType;
this.extractor = extractor;
this.process = new RecordProcessor<>();
}
#Override
public void run() {
// your implementation...
}
}
private static ProcessConsumerFactory instance = new ProcessConsumerFactory();
private Map<ProcessType, ProcessDataExtractor> extractorsByProcessName;
private ProcessConsumerFactory() {
extractorsByProcessName = new HashMap<>();
extractorsByProcessName.put(ProcessType.A, new ProcessDataExtractorA());
extractorsByProcessName.put(ProcessType.B, new ProcessDataExtractorB());
// add a new element in the map to add a new mapping
}
public static ProcessConsumerFactory getInstance() {
return instance;
}
public IProcessConsumer createNewProcessConsumer(ProcessType processType) {
ProcessDataExtractor extractor = extractorsByProcessName.get(processType);
if (extractor == null) {
throw new IllegalArgumentException("processType " + processType + " not recognized");
}
IProcessConsumer processConsumer = new ProcessConsumer(processType, extractor);
return processConsumer;
}
}
Now the clients of the Process consumers class could instante them like that:
IProcessConsumer processConsumer = ProcessConsumerFactory.getInstance().createNewProcessConsumer(ProcessType.A);
Also the way I have my abstract class Validator is right? It is not
doing any useful things at all looks like.
You use an abstract class for validators but for the moment you have not move common behavior in this abstract class, so you could use an interface :
public interface ProcessDataExtractor{
Optional<DataHolder> getDataHolder(ProcessType processType, Record record);
}
You could introduce the abstract class later if it becomes suitable.
There are a few problems with your design:
Catch invalid data as early as possible.
Post-construction is not the right way. Once an object, in this case Record, is constructed it should have valid state. Which means, your validation should be performed prior to constructing Record.
Get data from somehere: from web, database, text file, user input or whatever.
Validate data.
Construct Record object. At this point, either Record object has valid state, or it fails construction for example by raising exception.
Now, if the source from which you get data, contains mostly invalid data, it should be dealt there. Because that is a problem in itself. If the source is right but reading or getting the data has problems, it should be solved first.
Assuming the above issues, if exists, solved then the sequence of program should be something like this.
// Get the data from some source
// Perform Validation on the data. This is generic validation, like validation // of data read from an input form etc.
validate deviceId
validate payId
validate clientId
...
if invalid do something
else if valid proceed
// construct Record object
Record record = new Record(deviceId, payId, clientId, ...)
// At this point record has valid data
public class Record {
deviceId
payId
clientId
Record(deviceId, payId, clientId, ...) {
// Perform business rule validation, pertaining to Record's requirements.
// For example, if deviceId must be in certain range etc.
// if data is valid, perform construction.
// else if invalid, don't construct. throw exception or something
// to deal with invalid condition
}
}
Another problem is, you use some utils class to extract internal data from Record. That is not right either. Record itself should provide getters to its attributes. Right now, what is related to Record is scattered between
Record, Utils, and Validator.
I think your code needs a thorough re-evaluation. I suggest, take a pause, start again but this time at a higher level. Start designing without code for example with some sort of diagramming. Start with only box and arrows (Something like a class diagram but don't need to use a UML tool etc. Pencil and paper. Decide what should go where. Things like,
what are the entities you are dealing with.
What properties each entity has, attributes, methods etc.
What is the relationship among these entities
Consider the sequence these entities are used or interact, then keep refining it.
Without this high level view, dealing with the design question at the code level is difficult and almost always gives bad results.
Once you dealt with the design at a higher level. Then, putting that in code is much easier. Of course you can refine it at that level too, but high level structure should be considered first.

Multiple Parameters or is there any way to force use of setters (Java)?

I have a java class named Transactions, with several methods. On in particular, inserts in Sqlite database all values representing a new transaction, something like this:
Date; Time; Category; Payee; Payer; Value; Tags; Description (...)
When I call the method to save a new Transaction, it looks like:
new Transactions().saveNewTransaction(String date, String time, String category, Int Payee, Int Payer, String value, String tags, String Description (...)
I think this method seems big, bad for readable code and the best way would be those fields be as variables from Transactions class and the method saveNewTransaction(), takes no parameters but instead accessing the variables inside the class.
The only problem is: how can I force to a class (In my case an Activity class) call all setters needed to save a new transaction?
The risk would be call saveNewTransaction() and several fields with values not set by the Activity class (at least the method assures all fields must be set by the caller)
Thanks!
If your requirement is that each created Transactions object should result in some database entry, you could consider dropping the saveNewtTransaction method and instead perform the save-action within some "builder" class:
public class TransactionBuilder {
private Date date;
public TransactionsBuilder with(#NonNull Date date){
this.date = date;
return this;
}
public Transaction build(){
validateFields();
Transaction transaction = new Transaction();
transaction.set(date);
createADatabaseEntry(transaction);
return transaction;
}
private void validateFields() {
org.springframework.util.Assert.notNull(date, "The date cannot be null.");
}
Have the checker framework issue compiler warnings, when developers try to pass null to setters annotated with #NonNull.
Obviously, in your case, the builder would have some different with()-methods, namely some which matches what is needed for your Transactiion object / saveNewTransaction()-method.
Ps I have not given it any thought what your Transaction class is all about. But if the Transactions class only has that one method, I would create a variant of above mentioned solution:
Create an interface with a single method that defines the functionality.
Create an implementation which contains the logic of your saveNewTransactions()-method. Only difference being that this method should only accept a single argument, which is an "input bean", fx TransactionInputBean.
Create your input bean (a simply class with private fields, and public getters&setters.
Create a builder for the input bean.
you could leave all of these variables uninitialized or set them to a value that shouldn't occur by the setters (eg. -1).
Then in your new Transactions().save(); you'd need to check if they still have that value.
But this solution won't work in the way you wrote above, because you are already saving the transaction when you create the object. And here you'd need to create the new object first and then call all the setters.
Your transactions class could look like this:
package de.jeanma.stackOverflow;
import java.lang.Integer;
import java.lang.String;
public class Transactions{
private String date, time, category, value, tags, description;
private int payee, payer;
public Transactions(){
//Add everything here, needed for the constructor
}
public Transactions(String date, String time, String category, int payee, //I recommend creating an constructor that sets the values as well, beacause you
int payer, String value, String tags, String Description){ // might want to create the object and call the save() directly withoud calling every setter one by one
this.date = date;
this.time = time;
this.category = category;
this.value = value;
this.tags = tags;
this.description = description;
this.payee = payee;
this.payer = payer;
//Add everything here, needed for the constructor as well
}
//Here you can place all your other methods
public void save(){
if(!(isInitialized(date) && isInitialized(time) && isInitialized(category) && isInitialized(value) //here all values are checked if they are initialized.
&& isInitialized(tags) && isInitialized(description) && isInitialized(Integer.valueOf(payee)) //The primitive int's are made to complex Integer's because
&& isInitialized(Integer.valueOf(payer)))){ // the method isInitialized() expects an object
//here you could throw an exception or do something like: System.exit(-1);
}
}
private boolean isInitialized(Object Obj){ // this is the method that's checking if the value is initialized
if(Obj.equals(null)) return false;
else return true;
}
//Add all the setters here (I'm too lazy to do that now)
}
I hope that this awnser satisfies you.

Need to pass multiple (20+) parameters in a Java method. Any efficient way of doing this?

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/

Struts 2 and business objects

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.

Categories

Resources