Alternative to multiple constructors - java

I have this constructor...
public ShiftLog(String companyName, boolean workedForAgent, String agentName,
Date shiftStart, Date shiftEnd,
boolean breakTaken, Date breakStart,
Date breakEnd, boolean isTransportJob,
String transportCompanyName, String vehicleRegistration) {
this.userUid = FirebaseAuth.getInstance().getCurrentUser().getUid();
this.companyName = companyName;
this.workedForAgent = workedForAgent;
this.agentName = agentName;
this.shiftStart = shiftStart;
this.shiftEnd = shiftEnd;
this.breakTaken = breakTaken;
this.breakStart = breakStart;
this.breakEnd = breakEnd;
this.isTransportJob = isTransportJob;
this.transportCompanyName = transportCompanyName;
this.vehicleRegistration = vehicleRegistration;
}
Now I want to add in a shift log (instantiate a shift log object for a user). The problem is that there are multiple combinations a shift log can have. For example, workedForAgent is false, there should be no need to pass in agentName. How can I do that without creating multiple constructors because there can be multiple possible combinations? For example, user can work for agent but not take a break, meaning break start time and end time shouldn't be needed to pass in. But that would require so many constructors for all possible combinations. Any alternative?
Also I am using the room database to append all this info. So if workedForAgent is false for example, automatically set agentName to null. How could that be done as well.

Take a look at Builder patterns.
Builder pattern is a creational design pattern it means its solves problem related to object creation.
It typically solve problem in object oriented programming i.e determining what constructor to use.

Adding to #Kodiak
You can replace your constructor with builder in few clicks
as mentioned here https://www.jetbrains.com/help/idea/replace-constructor-with-builder.html
Plus, the best part is,it will refactor all the occurrence of the constructor with builder automatically

Short Answer: Use Getters/Setters
Long Answer: The alternative method here is that you can instantiate the variables that you sure they must exist in the constructor and then the other conditional variables can be defined with setter methods and you can easily fetch with getters.
public class ShiftLog {
private Object userUid;
private String companyName;
private boolean workedForAgent;
private String agentName;
private Date shiftStart;
private Date shiftEnd;
private boolean breakTaken;
private Date breakStart;
private Date breakEnd;
private boolean isTransportJob;
private String transportCompanyName;
private String vehicleRegistration;
public ShiftLog(String companyName, Date shiftStart, Date shiftEnd) {
this.userUid = FirebaseAuth.getInstance().getCurrentUser().getUid();
this.companyName = companyName;
this.shiftStart = shiftStart;
this.shiftEnd = shiftEnd;
}
public boolean isWorkedForAgent() {
return workedForAgent;
}
public void setWorkedForAgent(boolean workedForAgent) {
this.workedForAgent = workedForAgent;
}
public String getAgentName() {
return agentName;
}
public void setAgentName(String agentName) {
this.agentName = agentName;
}
public boolean isBreakTaken() {
return breakTaken;
}
public void setBreakTaken(boolean breakTaken) {
this.breakTaken = breakTaken;
}
public Date getBreakStart() {
return breakStart;
}
public void setBreakStart(Date breakStart) {
this.breakStart = breakStart;
}
public Date getBreakEnd() {
return breakEnd;
}
public void setBreakEnd(Date breakEnd) {
this.breakEnd = breakEnd;
}
public boolean isTransportJob() {
return isTransportJob;
}
public void setTransportJob(boolean isTransportJob) {
this.isTransportJob = isTransportJob;
}
public String getTransportCompanyName() {
return transportCompanyName;
}
public void setTransportCompanyName(String transportCompanyName) {
this.transportCompanyName = transportCompanyName;
}
public String getVehicleRegistration() {
return vehicleRegistration;
}
public void setVehicleRegistration(String vehicleRegistration) {
this.vehicleRegistration = vehicleRegistration;
}
}

Related

Which design pattern reduces repetition in this validation inputs code

Want to reduce code from these validations, these validators' classes verify and return if inputs are valid or invalid, it's a reduction, I will validate some panels and almost 40 fields. Want to see if there is some pattern to simplify this, code is more than 300 lines which I believe to be a bad practice.
package Validation1;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MinimalReproducibleExampleValidation {
public static void main(String[] args) {
boolean saveToDatabase = true;
String name = "Richard";
String idCard = "123456789";
String address = "Main Street 454";
Entity entity = new Entity ();
/// Name Validation
if (saveToDatabase) {
ValidationEntity nameValidation = new
ValidationEntity(ValidationEntity.Regex.Alphabetic,
name, "ID Card", 0, 13);
saveToDatabase = nameValidation.isValid();
entity.setName(name);
}
/// ID Card Validation
if (saveToDatabase) {
ValidationEntity idCardValidator = new
ValidationEntity(ValidationEntity.Regex.Numerical,
idCard, "ID Card", 0, 13);
saveToDatabase = idCardValidator.isValid();
entity.setIdCard(idCard);
}
/// EMail Validation
if (saveToDatabase) {
ValidationEntity emailValidator = new
ValidationEntity(ValidationEntity.Regex.AlphaNumerical,
address, "Address", 1, 9);
saveToDatabase = emailValidator.isValid();
entity.setAddress(address);
}
// If every field is valid, save
if (saveToDatabase) {
new EntityDao().save(entity);
}
}
}
and:
class ValidationEntity {
private Regex regex;
private String input;
private String errorMessage;
private Integer minimum;
private Integer maximum;
public ValidationEntity(Regex regex, String input, String errorMessage, int minimum, int maximum) {
this.regex = regex;
this.input = input;
this.errorMessage = errorMessage;
this.minimum = minimum;
this.maximum = maximum;
}
public boolean isValid() {
Pattern pattern = Pattern.compile(getRegexFormat(), Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(input);
return matcher.matches();
}
public String getRegexFormat() {
return "^" + regex.getRegex() + "{" + minimum + "," + maximum + "}";
}
and:
public enum Regex {
LowercaseAlphabetic("[a-z]"), UppercaseAlphabetic("[A-Z]"), Numerical("[0-9]"), Alphabetic("[a-zA-Z]"),
AlphaNumerical("^[A-Za-z0-9_ ]*$");
public String regexValue;
Regex(String regexValue) {
this.regexValue = regexValue;
}
}
}
and:
class EntityDao {
public void save(Entity entity) {
System.out.println("Saving the model!");
}
}
and:
class Entity {
private String name;
private String idCard;
private String address;
public void setIdCard(String idCard) {
this.idCard = idCard;
}
public void setName(String name) {
this.name = name;
}
public void setAddress(String address) {
this.address = address;
}
public String getIdCard() {
return idCard;
}
public String getIdName() {
return name;
}
public String getAddress() {
return address;
}
}
We have a repetetive behaviour:
if (saveToDatabase) {
ValidationEntity nameValidation = new
ValidationEntity(ValidationEntity.Regex.Alphabetic,
name, "ID Card", 0, 13);
saveToDatabase = nameValidation.isValid();
entity.setName(name);
// create ValidationEntity object
// check whether entity is valid
// set some attribute value
}
I would suggest:
to collect all validation logic in one place
set some attribute values after validation is completed
and then save to database
By doing the above actions, we will separate our validation logic, variable assignments and saving database. So our code should comply with Single Responsibility principle of SOLID principles.
So let's put repetetive behaviour in some abstraction. I am sorry, I am not Java guy. Let me show via C#. But I've provided comments of how code could look in Java:
public abstract class FieldValidation
{
// I am not Java guy, but if I am not mistaken, in Java,
// if you do not want method to be overriden, you shoud use `final` keyword
public abstract bool IsValid();
}
And its concrete implementations:
public class IdCardFieldValidation : FieldValidation // extends in Java
{
public override bool IsValid() // #Override in Java
{
// your code here:
/*ValidationEntity nameValidation = new
ValidationEntity(ValidationEntity.Regex.Alphabetic,
name, "ID Card", 0, 13);
return nameValidation.isValid();*/
return true;
}
}
public class EmailFieldValidation : FieldValidation // extends in Java
{
public override bool IsValid() // #Override in Java
{
// your code here:
/*ValidationEntity emailValidator = new
ValidationEntity(ValidationEntity.Regex.AlphaNumerical,
address, "Address", 1, 9);
returnr emailValidator.isValid();*/
return true;
}
}
And then we can create a class which will have all validations. And this class will return whether all validations were okay:
public class AllFieldValidations
{
private List<FieldValidation> _fieldValidations = new List<FieldValidation>()
{
new IdCardFieldValidation(),
new EmailFieldValidation()
};
public bool IsValid()
{
foreach (var fieldValidation in _fieldValidations)
{
if (!fieldValidation.IsValid())
return false;
}
return true;
}
}
And then your method will look like this:
AllFieldValidations allFieldValidations = new AllFieldValidations();
bool isAllFieldsValid = allFieldValidations.IsValid();
if (!isAllFieldsValid)
return;
SetAttributes();
SaveToDatabase();
and implementations of other methods:
public void SetAttributes
{
entity.setName(name);
entity.setIdCard(idCard);
entity.setAddress(address);
}
public void SaveToDatabase()
{
new EntityDao().save(entity);
}
So here we've applied Single responsibility principle here of SOLID principles.
I mean we do not have almighty method that has all validations, setting attributes and saving to database.
Pros of this approach:
highly testable code
great separation of concerns
improved readability. We've created methods with self explanatory names

#RestController autoserialize POJO's

I have a Spring mvc application, with a #RestController like such:
#RestController
#RequestMapping("levels")
public class LevelController {
private final GetLevelOneCount getLevelOneCount;
private final GetLevelTwoCount getLevelTwoCount;
private final GetLevelThreeCount getLevelThreeCount;
#Inject
public LevelController(GetLevelOneCount getLevelOneCount,
GetLevelTwoCount getLevelTwoCount,
GetLevelThreeCount getLevelThreeCount) {
this.getLevelOneCount = getLevelOneCount;
this.getLevelTwoCount = getLevelTwoCount;
this.getLevelThreeCount = getLevelThreeCount;
}
#GetMapping("/level1/{id}")
public LevelModel levelOne(#PathVariable String id) throws SQLException {
LevelModel levelOneModel = new LevelModel();
levelOneModel.setLevelQuery(getLevelOneCount.execute(id));
levelOneModel.setLevelDirQuery(getLevelOneCount.executeDir(id));
levelOneModel.setLevelDateQuery(getLevelOneCount.executeDate(id));
return levelOneModel;
}
my LevelModel is a POJO with private variables, now i wonder, if this can get serialized to propper JSON with private variables?
package com.pwc.tag.service.levels;
public class LevelModel {
private Long LevelQuery;
private Long LevelDirQuery;
private Long LevelDateQuery;
public Long getLevelQuery() {
return LevelQuery;
}
public void setLevelQuery(Long levelQuery) {
LevelQuery = levelQuery;
}
public Long getLevelDirQuery() {
return LevelDirQuery;
}
public void setLevelDirQuery(Long levelDirQuery) {
LevelDirQuery = levelDirQuery;
}
public Long getLevelDateQuery() {
return LevelDateQuery;
}
public void setLevelDateQuery(Long levelDateQuery) {
LevelDateQuery = levelDateQuery;
}
}
Yes, your object will be serialized to a proper JSON structure including the private field, because of the getters and setters.
If these fields should not be present in the output object, you can add the #JsonIgnore annotation to exclude them from the JSON structure.
P.S. the common approach is to start names of java properties with a lower case letter.

How to override the #AdminPresentation for existing attributes [Broadleaf Commerce]

I am trying to override the #AdminPresentation of the following attribute defined in ProductImpl:
#Column(name = "DISPLAY_TEMPLATE")
#AdminPresentation(friendlyName = "ProductImpl_Product_Display_Template",
group = GroupName.Advanced)
protected String displayTemplate;
Currently, it is displayed as a text field by default as there is no fieldType attribute provided. But I want to display a dropdown select menu with predefined values such as Product and Plan. Here is what I've tried so far:
I've created a class DisplayTemplateType that implements BroadleafEnumerationType and defined PLAN and PRODUCT enums. Here is the code of that class:
public class DisplayTemplateType implements Serializable, BroadleafEnumerationType {
private static final long serialVersionUID = 7761108654549553693L;
private static final Map<String, DisplayTemplateType> TYPES = new LinkedHashMap<String, DisplayTemplateType>();
public static final DisplayTemplateType PLAN = new DisplayTemplateType("PLAN", "PLAN");
public static final DisplayTemplateType PRODUCT = new DisplayTemplateType("PRODUCT", "PRODUCT");
public static DisplayTemplateType getInstance(final String type) {
return TYPES.get(type);
}
private String type;
private String friendlyType;
public DisplayTemplateType() {
//do nothing
}
public DisplayTemplateType(final String type, final String friendlyType) {
this.friendlyType = friendlyType;
setType(type);
}
#Override
public String getType() {
return type;
}
#Override
public String getFriendlyType() {
return friendlyType;
}
private void setType(final String type) {
this.type = type;
if (!TYPES.containsKey(type)) {
TYPES.put(type, this);
} else {
throw new RuntimeException("Cannot add the type: (" + type + "). It already exists as a type via " + getInstance(type).getClass().getName());
}
}
// equals() and hashCode() implementation is removed for readability
}
Then in applicationContext-admin.xml file, I have added the following override properties:
<mo:override id="blMetadataOverrides">
<mo:overrideItem ceilingEntity="org.broadleafcommerce.core.catalog.domain.Product">
<mo:field name="displayTemplate">
<mo:property name="explicitFieldType" value="BROADLEAF_ENUMERATION"/>
<mo:property name="broadleafEnumeration" value="com.community.core.domain.DisplayTemplateType"/>
</mo:field>
</mo:overrideItem>
</mo:override>
But it didn't change anything. Am I missing something here?
Finally, after trying many things, I came up with a workaround. Instead of going with the XML based approach, I had to extend the ProductImpl class to override #AdminPresentation of its attributes. But for extending I needed to define an #Entity and as a result, I needed to create a useless table to bind to that entity. I know this is not the perfect approach but I couldn't find any better solution for this. Here is my code, so that someone might get help from it in the future:
#Entity
#Immutable
#AdminPresentationMergeOverrides({
#AdminPresentationMergeOverride(name = "displayTemplate", mergeEntries = {
#AdminPresentationMergeEntry(propertyType = PropertyType.AdminPresentation.FIELDTYPE, overrideValue = "BROADLEAF_ENUMERATION"),
#AdminPresentationMergeEntry(propertyType = PropertyType.AdminPresentation.BROADLEAFENUMERATION, overrideValue = "com.community.core.domain.DisplayTemplateType"),
#AdminPresentationMergeEntry(propertyType = PropertyType.AdminPresentation.REQUIREDOVERRIDE, overrideValue = "REQUIRED"),
#AdminPresentationMergeEntry(propertyType = PropertyType.AdminPresentation.DEFAULTVALUE, overrideValue = "PLAN")
})
})
public class CustomProduct extends ProductImpl {
private static final long serialVersionUID = -5745207984235258075L;
}
This is how it is displayed now:

Spring ConstraintValidator customizing

Before asking questions, I apologize for not being good at English.
I'm implementing a custom ConstraintValidator for cross-field validation as shown below.
Validation Target Class
public class ValidationTarget {
#Valid
private Inner inner;
#ValidDates(fromField = "from", toField = "to",
message = "{from} must not be later than {to}")
public class Inner {
private Date from;
private Date to;
}
// ...
}
CustomConstraintValidator
// imports ...
public class CustomConstraintValidator implements ConstraintValidator<ValidDates, Object> {
private String fromFieldName;
private String toFieldName;
private String message;
#Override
public void initialize(ValidDatesvalidationSpec) {
this.fromFieldName = validationSpec.fromField();
this.toFieldName = validationSpec.toField();
this.message = validationSpec.message();
}
#Override
public boolean isValid(Object target, ConstraintValidatorContext ctx) {
Date startDateObject = getFieldValue(target, fromFieldName);
Date endDateObject = getFieldValue(target, toFieldName);
if (start.after(end)) {
addConstraintViolation(toFieldName, message, ctx);
return false;
}
return true;
}
private void addConstraintViolation(String propertyName, String message, ConstraintValidatorContext ctx) {
ctx.buildConstraintViolationWithTemplate(message)
.addPropertyNode(propertyName)
.addConstraintViolation()
.disableDefaultConstraintViolation();
}
private Date getFieldValue(Object instance, String fieldName) {
Field field = ReflectionUtils.findField(instance.getClass(), fieldName);
ReflectionUtils.makeAccessible(field);
return (Date) ReflectionUtils.getField(field, instance);
}
}
In the above code, Inner class object is returned when calling getInvalidValue() of ConstraintViolation.
I want to change this value only to a specific field value rather than to the entire Inner class.

Why am I able to pass Long to Map.get() method which is not keyed on Longs

I've run into some funky behavior with generics and I was wondering if someone could shed some light as to why this is happening. To start, I have a class Foo which has a field id. The hashCode method on Foo just returns the id. In another class I create a Map<Foo, Double> bar = new HashMap<Foo, Double().
Then, at a later part of the code the strangeness starts, and I am able to do the following (simplified here):
Long baz = new Long(1);
bar.get(baz);
So, my question is, Why doesn't the compiler and catch this and report it as an error?
EDIT: I made one mistake in my initial question in that get is the method that works, not put. I have posted the full code below.
Map<WebPage, Double> scoresForPhrase = new HashMap<WebPage, Double>();
// Now that we have a list of matching docs, we can calculate the
// Score of each word in the phrase for each document
for (String term: phrase.getWords()) {
TreeSet<Posting> wordPostings = wordMap.get(term);
for(Long doc: matchingDocs) {
if (docDenomScores.get(doc) == null) {
docDenomScores.put(doc, getDocTotal(doc));
}
// The set is of postings, which are compared by docId, so
// we need a temporary one to enable searching
Posting temp = new Posting(doc, new ArrayList<Integer>());
Posting wordPosting = wordPostings.ceiling(temp);
WebPage page = (WebPage) mWebpageDb
.getPageIdToWebPageTable().get(doc);
score = getTermScore(wordPosting, page,
wordPostings.size());
score = score * queryTermWeights.get(term);
Double curScore = scoresForPhrase.get(doc);
}
}
As for the Foo class, it is:
public class WebPage implements Serializable {
private static final long serialVersionUID = -4907557806357281837L;
private String mUrl;
private int mMaxTf;
private long mPageId;
private long mLastTimeUpdated;
private List<Long> mParentIds;
private long mContentLength;
private String mTitle;
private List<Long> mChildren;
private List<String> mAllUrls;
public WebPage(String url, long pageId, long lastTimeUpdated,
List<Long> parentIds, long contentLength, String title, List<Long> children,
List<String> allUrls) {
super();
this.mUrl = url;
this.mPageId = pageId;
this.mLastTimeUpdated = lastTimeUpdated;
this.mParentIds = parentIds;
this.mContentLength = contentLength;
this.mTitle = title;
this.mChildren = children;
this.mAllUrls = allUrls;
this.mMaxTf = 0;
}
public void setUrl(String mUrl) {
this.mUrl = mUrl;
}
public void setPageId(int mPageId) {
this.mPageId = mPageId;
}
public void setLastTimeUpdated(long mLastTimeUpdated) {
this.mLastTimeUpdated = mLastTimeUpdated;
}
public void setParentIds(List<Long> mParentId) {
this.mParentIds = mParentId;
}
public void setContentLength(long mContentLength) {
this.mContentLength = mContentLength;
}
public void setChildren(List<Long> mChildren) {
this.mChildren = mChildren;
}
public void setAllUrls(List<String> allUrls) {
this.mAllUrls = allUrls;
}
public void setMaxTf(int newTf) {
this.mMaxTf = newTf;
}
public String getUrl() {
return mUrl;
}
public long getPageId() {
return mPageId;
}
public long getLastTimeUpdated() {
return mLastTimeUpdated;
}
public List<Long> getParentIds() {
return mParentIds;
}
public long getContentLength() {
return mContentLength;
}
public List<Long> getChildren() {
return mChildren;
}
public String getTitle() {
return mTitle;
}
public List<String> getAllUrls() {
return mAllUrls;
}
public int getMaxTf() {
return mMaxTf;
}
#Override
public boolean equals(Object o) {
if (!(o instanceof WebPage)) {
return false;
} else {
return ((WebPage)o).mPageId == mPageId;
}
}
#Override
public int hashCode() {
return (int)mPageId;
}
public String toString() {
return mUrl;
}
}
So two things. First, remember that due to type-erasure there is no runtime checking of generic types. The Map<Foo, Double> simply becomes Map<Object, Object>.
Second, with regards to a compiler warning or error, you should get a warning or error if bar is declared of type Map<Foo, Double>. But if it is declared as Map, no warning or error. My guess is that bar is defined as Map bar.
UPDATE
The reason there is no error on get is that by definition get takes an Object not the generic type. It is one of the odd things about the interface.
Map.get
Your Map<Foo, Double> might have been casted to Map:
Map<Foo, Double> barOriginal = new HashMap<Foo, Double();
// ...
Map bar = barOriginal;
// ...
Long baz = new Long(1);
bar.put(baz, new Double(1));

Categories