I have a below class in which isValid method is being called.
I am trying to extract few things from Record object in the isValid method. And then I am validating few of those fields. If they are valid, then I am populating the holder map with some additional fields and then I am populating my DataHolder builder class and finally return the DataHolder class back.
If they are not valid, I am returning null.
Below is my class:
public class ProcessValidate extends Validate {
private static final Logger logger = Logger.getInstance(ProcessValidate.class);
#Override
public DataHolder isValid(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");
Long oldTimestamp = (Long) DataUtils.extract(record, "oldTimestamp");
Long newTimestamp = (Long) DataUtils.extract(record, "newTimestamp");
String clientId = (String) DataUtils.extract(record, "clientId");
if (isValidClientIdDeviceId(processName, deviceId, clientId) && isValidPayId(processName, payId)
&& isValidHolder(processName, holder)) {
holder.put("isClientId", (clientId == null) ? "false" : "true");
holder.put("isDeviceId", (clientId == null) ? "true" : "false");
holder.put("abc", (clientId == null) ? deviceId : clientId);
holder.put("timestamp", String.valueOf(oldTimestamp));
DataHolder dataHolder =
new DataHolder.Builder(record).setClientId(clientId).setDeviceId(deviceId)
.setPayId(String.valueOf(payId)).setHolder(holder).setOldTimestamp(oldTimestamp)
.setNewTimestamp(newTimestamp).build();
return dataHolder;
} else {
return null;
}
}
private boolean isValidHolder(String processName, Map<String, String> holder) {
if (MapUtils.isEmpty(holder)) {
// send metrics using processName
logger.logError("invalid holder is coming.");
return false;
}
return true;
}
private boolean isValidpayId(String processName, Integer payId) {
if (payId == null) {
// send metrics using processName
logger.logError("invalid payId is coming.");
return false;
}
return true;
}
private boolean isValidClientIdDeviceId(String processName, String deviceId, String clientId) {
if (Strings.isNullOrEmpty(clientId) && Strings.isNullOrEmpty(deviceId)) {
// send metrics using processName
logger.logError("invalid clientId and deviceId is coming.");
return false;
}
return true;
}
}
Is my isValid method doing lot of things? Can it be broken down in multiple parts? Or is there any better way to write that code?
Also I don't feel great with the code I have in my else block where I return null if record is not valid. I am pretty sure it can written in much better way.
Update:
In my case this is what I was doing. I am calling it like this:
Optional<DataHolder> validatedDataHolder = processValidate.isValid(processName, record);
if (!validatedDataHolder.isPresent()) {
// log error message
}
// otherwise use DataHolder here
So now it means I have to do like this:
boolean validatedDataHolder = processValidate.isValid(processName, record);
if (!validatedDataHolder) {
// log error message
}
// now get DataHolder like this?
Optional<DataHolder> validatedDataHolder = processValidate.getDataHolder(processName, record);
You are correct isValid() is doing too many things. But not only that, when most of us see a method that is called isValid() - we expect a boolean value to be returned. In this case, we're getting back and instance of DataHolder which is counterintuitive.
Try to split the things that you do in the method, for example:
public static boolean isValid(String processName, Record record) {
return isValidClientIdDeviceId(processName, record) &&
isValidPayId(processName, record) &&
isValidHolder(processName, record);
}
and then construct DataHolder in a different method, say:
public static Optional<DataHolder> getDataHolder(String processName, Record record) {
Optional<DataHolder> dataHolder = Optional.empty();
if (isValid(processName, record)) {
dataHolder = Optional.of(buildDataHolder(processName, record));
// ...
}
return dataHolder;
}
It will make your program easier to both read and maintain!
I think things start with naming here.
As alfasin is correctly pointing out, the informal convention is that a method named isValid() should return a boolean value. If you really consider returning a DataHolder; my suggestion would be to change name (and semantics a bit), like this:
DataHolder fetchHolderWithChecks(String processName, Record ...)
And I wouldn't return null - either an Optional; or simply throw an exception. You see, don't you want to tell your user about that error that occured? So when throwing an exception, you would have a mean to provide error messages to higher levels.
On validation itself: I often use something like this:
interface OneAspectValidator {
void check(... // if you want to throw an exception
boolean isValid(... // if you want valid/invalid response
And then various implementations of that interface.
And then, the "validation entry point" would somehow create a list, like
private final static List<OneAspectValidator> validators = ...
to finally iterate that list to validate those aspects one by one.
The nice thing about that approach: you have the code for one kind of validation within one dedicated class; and you can easily enhance your validation; just by creating a new impl class; and adding a corresponding object to that existing list.
I know this might not be directly actionable, but the first thing you should do if you want to clean up this code is to use OO (Object-Orientation). If you are not using OO properly, then there is no point arguing the finer details of OO, like SRP.
What I mean is, I couldn't tell what you code is about. Your classnames are "ProcessValidate" (is that even a thing?), "Record", "DataHolder". That is pretty suspect right there.
The string literals reveal more about the domain ("payId", "deviceId", "clientId") than your identifiers, which is not a good sign.
Your code is all about getting data out of other "objects" instead of asking them to do stuff (the hallmark of OO).
Summary: Try to refactor the code into objects that reflect your domain. Make these objects perform tasks specific to their responsibilities. Try to avoid getting information out of objects. Try to avoid setting information into objects. When that is done, it will be much more clear what SRP is about.
Related
Say I have a function that looks at a file and returns two results: recognized and unrecognized. When it returns the recognized result, I want the result to also contain a message but when it is unrecognized, no message is necessary.
public Result checkFile(File file) {
...
}
There are two ways I can think of to accomplish this...
Have the Result class like so:
class Result {
private Type type;
private String message;
enum Type {
RECOGNIZED, UNRECOGNIZED
}
}
Or do it like so:
class Result {
}
class Unrecognized extends Result {
}
class Recognized extends Result {
private String message;
}
I'm inclined to use the second method, even though I'd have to check the result using instanceof and I've read that instanceof should be avoided whenever possible, but doing this avoids having a null message when the result is unrecognized. For this example a null message wouldn't be much of an issue, but what if there is a lot more data associated with a recognized result? It seems like worse practice to me to instantiate a class that could have all null fields.
What is the best practice to handle this situation? Is there some standard method or pattern?
Two classes might be overkill, because of it being one and the same class of object. Also an enum with two values which merely reassemble true and false is not required. One class Result should suffice and this would also remove the demand for a common interface. I'd be all for "no complexity beyond necessary" ...
class RecognitionResult {
private String message = "default message";
private boolean recognized = false;
public Result() {}
public Result(boolean value) {
this.setRecognised(value);
}
public boolean setRecognised(boolean value) {
this.recognized = value;
}
public boolean setMessage(#NonNull String value) {
this.message = value;
}
public boolean getRecognised() {
return this.recognized;
}
#Nullable
public String getMessage() {
return this.recognized ? this.message : null;
}
}
then one can simply do:
return new RecognitionResult(true);
an interface for asynchronous callbacks might look alike this:
interface Recognition {
void OnComplete(RecognitionResult result);
}
or if you really want to optimize:
interface Recognition {
void OnSuccess(RecognitionResult result);
void OnFailure(RecognitionException e);
}
Of course there's no 'correct' design here - it's going to be a matter of opinion which way you go. However my view is that the modern trend in OOD is to minimise the use of extension and to use delegation and implementation of interfaces wherever possible.
As a general rule, whenever you think of using instanceof, reconsider your design.
This would be my suggestion:
interface Result {
boolean isRecognised();
String getMessage();
}
class RecognisedResult implements Result {
private final String message;
public boolean isRecognised() {
return true;
}
public String getMessage() {
return message;
}
}
class UnrecognisedResult implements Result {
public boolean isRecognised() {
return false;
}
public String getMessage() {
throw new UnsupportedOperationException("No message for unrecognised results");
}
}
you can look at the way Retrofit implement your concept of "recognised" and "message"
https://square.github.io/retrofit/2.x/retrofit/retrofit2/Response.html. it is similar to your first method.
what they did is to have a class called Response, containing a method called isSuccessful(), and a method called body() containing the payload if it's successful (or null if it is unsuccessful.
you can try some thing like the following
class Result {
private Type type;
private String message;
public bool isSuccessful(){
return type == RECOGNIZED;
}
public String getMessage(){
return message; //null if unrecognized.
}
enum Type {
RECOGNIZED, UNRECOGNIZED
}
}
The functional way to do this would be to use an Either type, which doesn’t come with the JDK, but is available in vavr library. Based on your comments on this thread, it appears you don’t clearly understand how type inheritance works. In that case, a functional solution may be overkill, and I’d suggest going with #sprinter’s solution.
I'm trying to refactor my code, because methods I created are very similar. Even intelliJ emphasises it. Aim of methods is to map (using switch statements) type 'MessageType' to also 'MessageType', which is from different package. The problem is that input types for switch statement are also from different packages.
private MessageType convertToInsurancePolisyMessageType1 (pl.different.MessageType messageType) {
switch (messageType) {
case WARN: return MessageType.WARN;
case INFO: return MessageType.INFO;
case ERROR: return MessageType.ERROR;
default: throw new IllegalArgumentException(messageType.name());
}
}
private MessageType convertToInsurancePolisyMessageType2 (com.other.MessageType messageType) {
switch (messageType) {
case WARNING: return MessageType.WARN;
case INFO: return MessageType.INFO;
case ERROR: return MessageType.ERROR;
default: throw new IllegalArgumentException(messageType.name());
}
}
Is there any easy way to refactor this? Or should I leave like this?
Well, after all I don't see nothing bad with your switch approach:)
Just to throw some alternative you can use maps:
public class MessageTypeConverter {
private static final Map<pl.different.MessageType, com.other.MessageType> DIRECT_MAPPING =
new EnumMap<pl.different.MessageType, com.other.MessageType>(pl.different.MessageType.class) {{
put(pl.different.MessageType.WARN, com.other.MessageType.WARN);
put(pl.different.MessageType.INFO, com.other.MessageType.INFO);
put(pl.different.MessageType.ERROR, com.other.MessageType.ERROR);
}};
private static final Map<com.other.MessageType, pl.different.MessageType> REVERSE_MAPPING =
new EnumMap<com.other.MessageType, pl.different.MessageType>(com.other.MessageType.class) {{
put(com.other.MessageType.WARN, pl.different.MessageType.WARN);
put(com.other.MessageType.INFO, pl.different.MessageType.INFO);
put(com.other.MessageType.ERROR, pl.different.MessageType.ERROR);
}};
private com.other.MessageType convertToInsurancePolisyMessageType1(pl.different.MessageType messageType) {
return DIRECT_MAPPING.computeIfAbsent(messageType, key -> throw new IllegalArgumentException(messageType.name()));
}
private pl.different.MessageType convertToInsurancePolisyMessageType2(com.other.MessageType messageType) {
return REVERSE_MAPPING.computeIfAbsent(messageType, key -> throw new IllegalArgumentException(messageType.name()));
}
}
I'm afraid that there is no work around to have some sort of listing/mapping between values of each of the input MessageType and the returned one.
Perhaps you could try to do some reflection based approach considering that names are very similar... however I think that would bring nothing but problems down the road if such names change and it has a performance hit if you are doing this transformation often.
To complement other answers based on static maps, which are quite fine btw, if you have control on the code return MessageType enum (i.e. you are developing such enum) I think that you should consider to encapsulate the conversion within that enum by overloading the same name for each type of argument.
There are several option here... I personally prefer of for the name. valueOf is acceptable but since valueOf(String) would throw an NoSuchElementException you should keep that behavior. Let's stick to of here:
enum MessageType {
WARN, INFO, ERROR;
private static Map<pl.different.MessageType, MessageType> byPlDiffMType =
new EnumMap<>(Map.of(
pl.different.MessageType.WARN, WARN,
pl.different.MessageType.INFO, INFO,
pl.different.MessageType.ERROR, ERROR
));
private static Map<com.other.MessageType, MessageType> byCOthMType =
new EnumMap<>(Map.of(
com.other.MessageType.WARNING, WARN,
com.other.MessageType.INFO, INFO,
com.other.MessageType.ERROR, ERROR
));
public static MessageType of(pl.different.MessageType value) {
return of(byPlDiffMType, value);
}
public static MessageType of(com.other.MessageType value) {
return of(byCOthMType, value);
}
private static <V> MessageType of(Map<V, MessageType> map, V value) {
final MessageType result = map.get(value);
if (result == null) {
throw new IllegalArgumentException();
} else {
return result;
}
}
}
Even if you dont have control on that class source you probably better of performance wise using EnumMap rather than regular Maps (e.g. HashMap).
I know that you are not saving much code though ... but I think that conversion into a enum make sense to be encapsulated in the enum class itself if you are developing it.
The only way to reduce line is to do some kind of matching thru the common names adding ifs for those that are different but I would not encourage to do that as it would break silently with changes down the road and is probrably less "performy".
Something like this (with credit to RealSkeptic - sorry your comment appeared after I started writing this, but the same thing!):
public class DifferentMessageTypeConverter {
public enum DifferentMessageType {
WARNING, INFO, ERROR;
}
public enum InsurancePolicyMessageType {
WARN, INFO, ERROR;
}
private static final Map<DifferentMessageType, InsurancePolicyMessageType> DIFF_TO_INS_MAPPING;
static {
DIFF_TO_INS_MAPPING = new HashMap<>();
DIFF_TO_INS_MAPPING.put(DifferentMessageType.WARNING, InsurancePolicyMessageType.WARN);
DIFF_TO_INS_MAPPING.put(DifferentMessageType.INFO, InsurancePolicyMessageType.INFO);
DIFF_TO_INS_MAPPING.put(DifferentMessageType.ERROR, InsurancePolicyMessageType.ERROR);
}
public InsurancePolicyMessageType convertToInsurancePolisyMessageType1(DifferentMessageType dmt) {
dmt = Optional.ofNullable(dmt)
.orElseThrow(() -> new IllegalArgumentException("dmt must not be null"));
return Optional.ofNullable(dmt)
.map(DIFF_TO_INS_MAPPING::get)
.orElseThrow(() -> new IllegalArgumentException(messageType.name()));
}
}
This is a general issue/problem that I have come across. I wondered if anyone knows of any well suited design patterns or techniques.
private ExternalObject personObject;
private String name;
private int age;
private String address;
private String postCode;
public MyBuilderClass(ExternalObject obj)
this.personObject=obj;
build();
}
public build() {
setName(personObject.getName());
setAge(personObject.getAge());
setAddress(personObject.getAddress());
setPostCode(personObject.getPostCode());
.
.
. many more setters
}
The class above takes external objects from a queue and constructs MyBuilderClass objects.
A MyBuilderClass object is successfully built if all of the fields have been set to non-null non-empty values.
There will be many MyBuilderClass objects that cannot be built because data will be missing from the ExternalObject.
My problem, what is the best way to detect if an object has been correctly built?
I could check for null or empty values in the set methods and throw an exception. The problem with this approach is throwing exceptions is expensive and it will clogg the log files up because there will be many instances where an object cannot be built;
What other approaches could I use?
Correct me if I'm wrong: you are trying to find a good way to check if an object is valid, and if it is not, tell the client code about this without using an exception.
You can try a factory method:
private MyBuilderClass(ExternalObject obj)
this.personObject=obj;
build();
}
public static MyBuilderClass initWithExternalObject(ExternalObject obj) {
// check obj's properties...
if (obj.getSomeProperty() == null && ...) {
// invalid external object, so return null
return null;
} else {
// valid
MyBuilderClass builder = new MyBuilderClass(obj);
return builder.build();
}
}
Now you know whether an object is valid without using an exception. You just need to check whether the value returned by initWithExternalObject is null.
I wouldn't throw exceptions in cases that aren't exceptional. And as the only way for a constructor not to produce an object is to throw, you should not delay validation to the constructor.
I'd still recommend the constructor to throw if its results were to be invalid, but there should be a validation before that, so you don't even call the constructor with an invalid ExternalObject.
It's up to you if you want to implement that as a static method boolean MyBuilderClass.validate(ExternalObject) or by using the builder pattern with this validation.
Another approach for such a validation is to use java Annotations:
Make a simple annotaion class, let's say Validate:
#Target({ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
#interface Validate {
boolean required() default true;
}
then annotate the fields you want to be present as #Validate(required=true):
class MyBuilderClass {
private ExternalObject externalObject;
#Validate(required=true)
private String name;
#Validate(required=false) /*since it's a primitive field*/
private int age;
#Validate(required=true)
private String address;
#Validate(required=true)
private String postCode;
MyBuilderClass(ExternalObject externalObject) {
this.externalObject = externalObject;
build();
}
public void build() {
setName(personObject.getName());
setAge(personObject.getAge());
setAddress(personObject.getAddress());
setPostCode(personObject.getPostCode());
}
//.
//.
//. many more setters
}
And then add this method in the MyBuilderClass class, in order to check if your Object is built correctly:
public boolean isCorrectlyBuilt() throws IllegalAccessException {
boolean retVal = true;
for (Field f : getClass().getDeclaredFields()) {
f.setAccessible(true);
boolean isToBeChecked = f.isAnnotationPresent(Validate.class);
if (isToBeChecked) {
Validate validate = f.getAnnotation(Validate.class);
if (validate.required()/*==true*/) {
if (f.get(this) == null) {
retVal = false;
break;
/* return false; */
}
}
}
}
return retVal;
}
Here is an example of use :
public static void main(String[] args) throws Exception {
ExternalObject personObject = new ExternalObject();
personObject.setAge(20);
personObject.setName("Musta");
personObject.setAddress("Home");
personObject.setPostCode("123445678");
MyBuilderClass myBuilderClass = new MyBuilderClass(personObject);
System.out.println(myBuilderClass.isCorrectlyBuilt());
}
Output : true because the object is correctly built.
This will allow you to choose the fields that you want to be in the structure by reflection, without bringing those inherited from a base class.
As this previous answer suggests, here are 2 options either of which should be added after you have tried to set the variables.
use reflection to check whether any of the variables are null. (As mentioned in comments this will check all fields in this object but be careful with fields in any superclasses).
public boolean checkNull() throws IllegalAccessException {
for (Field f : getClass().getDeclaredFields())
if (f.get(this) != null)
return false;
return true;
}
perform a null check on each variable.
boolean isValidObject = !Stream.of(name, age, ...).anyMatch(Objects::isNull);
Previous answer
From what I've come across you could overwrite the equals method of your object and compare it with a valid example object. Its dirty and might only work in some cases.
Your approach is the best I could think of. Write a seperate method or class that has for example a static validate method. You could reuse it anywhere.
I have one class, let's call it ClassA, and a bunch of subclasses of it, and subsequent subclasses of those classes. ClassA, and every class below it takes a String at an argument in their constructor. I have a bunch of String objects that I need to 'convert' into subclasses of ClassA.
The current way I am doing it is with is isType(String) method that checks if the String is an instance of that subclass, but it seems like very bad programming technique to use a huge if-else or switch-case statement to find the correct type of ClassA that the String is. It there a common way to go down a sub-class structure, or is the way that I have been doing it okay?
The purpose of this is that I am making a scripting language (for a fun project) and I need to be able identify what something is. (Data type that is)
Example code:
public static boolean isType(String data) {
data = data.trim();
return edu.ata.script.data.Boolean.isType(data)
|| edu.ata.script.data.Integer.isType(data)
|| edu.ata.script.data.Double.isType(data)
|| DATA_STORAGE.contains(data)
|| ReturningMethod.isType(data)
|| edu.ata.script.data.String.isType(data);
}
public static Data get(String data) {
data = data.trim();
/*:)*/ if (edu.ata.script.data.Boolean.isType(data)) {
return edu.ata.script.data.Boolean.get(data);
} else if (edu.ata.script.data.Integer.isType(data)) {
return edu.ata.script.data.Integer.get(data);
} else if (edu.ata.script.data.Double.isType(data)) {
return edu.ata.script.data.Double.get(data);
} else if (DATA_STORAGE.contains(data)) {
return (Data) DATA_STORAGE.get(data);
} else if (ReturningMethod.isType(data)) {
return ReturningMethods.getMethodValue(data);
} else if (edu.ata.script.data.String.isType(data)) {
// Last option because everything is accepted.
return edu.ata.script.data.String.get(data);
} else {
throw new RuntimeException("Could not parse data - " + data);
}
}
I was indeed understanding something totally different, so I'm re-editing this answer.
I suspect that you're working in some sort of importation script or something and that the edu.ata.script.data.* are the ClassB, ClassC, etc that you were writing and they know how to convert stuff from one format to another... (This is just guessing)
My suggestion to get rid of all the if then else in the get(String data) method is that you implement a chain of responsability. That way you can have a chain that registers the several edu.ata.script.data.* in a List and then you iterate through that list until one of them returns true for the isType(string) knowing which subclass you want to use to process the string.
To remove the list of ORs in the isType(String data) method is a bit trickier and probably this is a bit over enginnering, but you can do the following:
Look in your classpath for classes that are assignableFrom your class
Then when you would retrieve all the classes that were assignable by your own you would have to invoke via reflection the isType of each one to know the result
I know you might find yourself a bit lost regarding the 1st point, best way is to look into ResolverUtil class from Stripes Framework where they do that in the method loadImplementationsFromContextClassloader
It looks like you are trying to parse a string into an instance of the correct subclass, by passing it to each subclass's isType method until one says it can handle it. I would have each subclass register a parser object which can inspect the string and produce an initialised instance of the corresponding subclass if possible.
Interface for the Parsers:
package edu.ata.script.data;
interface ScriptParser {
public boolean isType(String data);
public Data get(String data) throws UnparsableException;
}
An example Data subclass:
package edu.ata.script.data;
public class Boolean extends Data {
// Empty constructor for reflection purposes
public Boolean() {};
public Boolean(String data) {
// Initialise from string
}
public ScriptParser getParser() {
return new ScriptParser() {
public boolean isType(String data) {
return "true".equals(data) || "false".equals(data);
}
public Data get(String data) throws UnparsableException {
if (isType(data)) {
return new edu.ata.script.data.Boolean(data);
} else {
throw new UnparsableException(data);
}
}
};
}
}
Then you can just build a list of classes into a collection before parsing:
List<ScriptParser> parsers = new LinkedList<>();
parsers.add(new edu.ata.script.data.Boolean().getParser());
parsers.add(new edu.ata.script.data.Integer().getParser());
parsers.add(new edu.ata.script.data.Double().getParser());
...
The above could also be achieved via reflection.
Then you can parse the data with a simple loop, no matter how many data types you end up supporting:
public Data get(String data) throws SyntaxErrorException {
for (ScriptParser sp:parsers) {
if (sp.isType(data)) {
try {
return sp.get(data);
} catch (UnparsableException e) {
// This shouldn't happen, but better safe than sorry!
e.printStackTrace();
}
}
}
throw new SyntaxErrorException(data);
}
I was wondering if this approach was correct :
public ITask getState()
{
statePredicate[Some predicate definition];
ITask nextRunnable = null;
try {
nextRunnable = Iterables.find((Iterable)queue, statePredicate);
}
catch (NoSuchElementException e)
{}
return nextRunnable;
}
The points on which I am wondering are :
should the predicate be cached as a member of the class ?
I do nothing with the catch, I do not even log it because it is
normal for my app to not find anything.
t return null because I do a final return.
Thank you for your input !
-
1) If the predicate is always the same, I would make it a static final class member.
2) There is also a version of Iterables.find that you can specify a default value to (assuming you're using Google Guava). Then you don't need to deal with the NoSuchElementException at all.
3) Is there a reason to cast queue to Iterable? If this is not necessary, then don't cast.
class MyClass {
private static final Predicate STATE_PREDICATE = new Predicate<ITask>() {
#Override
public boolean apply(ITask input) {
// ... your code here
}
};
public ITask getState() {
return Iterables.find(queue, STATE_PREDICATE, null);
}
}
If the exception is really the usual case in your approach than you should put at least a comment into the catch area to make clear for everyone who reads the code that it was intentional and not a mistake. In my opinion returning Null is something different, but it some circumstanced not avoidable.