How to remove The Cyclomatic Complexity - java

I have below method
public MsgEnum validateUser(String userId, String pwd, UserOperationEnum userOperatioEnum) {
try {
MstCredential mstUser = mstUserDAO.validateUser(userId);
if (null == mstUser) {
return MsgEnum.FG40010;
}
if (!pwd.equals(pUtil.decrypt(mstUser.getPassword()))) {
return MsgEnum.FG40010;
}
if (userOperatioEnum.getOprName().equals(mstUser.getOperation()) && mstUser.getStatus() == OperationStatusEnum.ACTIVE.getMsgCode()) {
return MsgEnum.FG20000;
}
return MsgEnum.FG50010;
}
catch(Exception e) {
LOGGER.error("Error occured while validateStoreUser: "+e.getMessage(),e);
MsgEnum.FG20020.setMsgDesc(MsgEnum.FG20020.getMsgDesc()+ e.getMessage());
return MsgEnum.FG20020;
}
}
I am getting this exception "The Cyclomatic Complexity of this method "validateUser" is 11 which is greater than 10 authorized."
How can I remove this exception?

You have to reduce the number of conditional branches of the method. Every condition increases the complexity.
So first, you should bundle the outcomes
if (null == mstUser) {
return MsgEnum.FG40010;
}
if (!pwd.equals(pUtil.decrypt(mstUser.getPassword()))) {
return MsgEnum.FG40010;
}
can be combined to
if (null == mstUser || !pwd.equals(pUtil.decrypt(mstUser.getPassword()))) {
return MsgEnum.FG40010;
}
but that does not yet remove the complexity, but makes further refactoring more simple.
Next step is refactor the conditions out into separeate method returning boolean
null == mstUser || !pwd.equals(pUtil.decrypt(mstUser.getPassword()))
to
boolean isPasswordValid(MstCredential mstUser, String pwd){
return null == mstUser || !pwd.equals(pUtil.decrypt(mstUser.getPassword()));
}
and
userOperatioEnum.getOprName().equals(mstUser.getOperation()) && mstUser.getStatus() == OperationStatusEnum.ACTIVE.getMsgCode()
to
boolean isOperationValid(MstCredential mstUser, UserOperationEnum userOperatioEnum){
return userOperatioEnum.getOprName().equals(mstUser.getOperation()) && mstUser.getStatus() == OperationStatusEnum.ACTIVE.getMsgCode();
}
So the final method looks like
public MsgEnum validateUser(String userId, String pwd, UserOperationEnum userOperatioEnum) {
try {
MstCredential mstUser = mstUserDAO.validateUser(userId);
if (isPasswordValid(mstUser, pwd)) {
return MsgEnum.FG40010;
}
if (isOperationValid(mstUser, userOperatioEnum)) {
return MsgEnum.FG20000;
}
return MsgEnum.FG50010;
}
catch(Exception e) {
LOGGER.error("Error occured while validateStoreUser: "+e.getMessage(),e);
MsgEnum.FG20020.setMsgDesc(MsgEnum.FG20020.getMsgDesc()+ e.getMessage());
return MsgEnum.FG20020;
}
}
if the complexity is still to high, you could further move the contents of the try-block into a separate method, returning a MsgEnum so the only concern of the method becomes to handle the exception.

since I don't have much details on how individual functions are called, you may want to create multiple functions (each for null value, wrong password and such) so that you do not have multiple execution paths in your function. Cyclomatic complexity of max 10 means your if-else or whatever other conditions cannot result in more than 10 ways to return from a function. In your case there are 11.

Related

Cleaner way for if-else condition

I have a method having multiple if-else conditions (which is growing with each new msg-type support)
public Message<?> doTransform(Message<String> message) throws TransformationException {
try {
MessageBuilder<String> messageBuilder = null;
String payload = message.getPayload();
String payloadSubStr = payload.substring(0, Math.min(payload.length(), 100));
if(payloadSubStr.contains("<Management>")){
messageBuilder = buildManagementMsg(message);
} else if (payloadSubStr.contains("<Administration>") || (payloadSubStr.contains("<OtherAdministationAlert>"))){
messageBuilder = buildAdminMessages(message);
} else if (payloadSubStr.startsWith("Council")){
messageBuilder = parseCouncilMessages(message);
} else if (payloadSubStr.indexOf("Security") >= 0
|| payloadSubStr.indexOf("OtherSecurityAlert") >= 0){
messageBuilder = buildSecurityMessages(message);
} else if ( payloadSubStr.indexOf("<Staff>") >= 0
|| payloadSubStr.indexOf("<OtherStaffAlert>") >= 0){
messageBuilder = buildStaffMessages(message);
} else if(payloadSubStr.indexOf("<Student>") >= 0) {
messageBuilder = buildStudentMessages(message);
}else {
messageBuilder = buildOtherMessages(message);
}
return messageBuilder.build();
} catch(Exception e) {
throw new TransformationException(e);
}
}
Reason for doing substring: To avoid complete msg traversing with each if/else condition
Reason for using contains/indexOf combination: Messages received by this method can vary
Wanted to replace these if/else statements with some more cleaner logic. Not getting if Switch/Enum can be used or need to use any pattern as suggested over https://www.baeldung.com/java-replace-if-statements.
Gone through various similar questions available but not getting anything. Any suggestion will be helpful.
Thanks
If you are concerned with the number of conditions you'd need to add you could introduce a list of "message builder factories" (for lack of a better name atm) that you could append to.
A factory would contain a predicate to test the substring for and a messageBuilder(...) method. Then you'd iterate over the factory, check each of the predicates and if execute messageBuilder() on the first that matches.
Example:
interface MessageBuilderFactory<T> {
boolean test(T payload);
MessageBuilder<T> messageBuilder(Message<T> message);
}
class ManagementMBFactory implements MessageBuilderFactory<String> {
boolean test(String payload) {
return payload.contains("Management");
}
MessageBuilder<String> messageBuilder(Message<String> message) {
//content of buildManagementMsg() here
}
}
And in your code:
List<MessageBuilderFactory<String>> factories = ... //get the list of factories from somewhere
for( MessageBuilderFactory<String> factory : factories) {
if( factory.test(payloadSubStr) {
messageBuilder = factory.messageBuilder(message);
}
}
An advantage of doing it that way would be that the list of possible message builder factories is easily available and classes can be kept small (not all those buildXxx() methods in one single class).
Alternatively, if your message payload allows for that, you could actually try to parse it (it looks like XML) and operate on events, i.e. elements being found. That might be faster in the case of many small payloads and a huge number of possible message builders.
People are divided on the idea of multiple return statements in java but in this case I think I would tend to do that:
if(payloadSubStr.contains("<Management>")){
return buildManagementMsg(message);
}
if (payloadSubStr.contains("<Administration>") || (payloadSubStr.contains("<OtherAdministationAlert>"))) {
return buildAdminMessages(message);
}
if (payloadSubStr.startsWith("Council")){
return parseCouncilMessages(message);
}
if (payloadSubStr.indexOf("Security") >= 0
|| payloadSubStr.indexOf("OtherSecurityAlert") >= 0){
return buildSecurityMessages(message);
}
if ( payloadSubStr.indexOf("<Staff>") >= 0
|| payloadSubStr.indexOf("<OtherStaffAlert>") >= 0){
return buildStaffMessages(message);
}
if (payloadSubStr.indexOf("<Student>") >= 0) {
return buildStudentMessages(message);
}
return buildOtherMessages(message);
Going one step further this could be done with a validation service.
public class ValidationService {
public boolean isManagement(String str) { return str.contains("<Management>");
// ... and so on
}
And you can inject the service into the code such that you have
if (validationService.isManagement(payloadSubStr)) {
return buildManagementMsg(message);
}
// ...
For a case with conditions currently in OR you could use a list in the service, for example
public boolean isSecurity(String str) {
for (String term : new String[]{"Security", "OtherSecurityAlert"}) {
if (str.contains(term)) {
return true;
}
}
return false;
}

How to make this Binary serach tree insert method work

I am implementing different methods in a binary search tree and am stuck on the insert method as it just doesn't seem to work.
I have been trying to implement the insert method for a while now but nothing seems to work it's always returning null. This method takes a user and adds it to the database. Using the User class.
public boolean beFriend(User friend) throws IllegalArgumentException {
User node = friend;
if (friend == null) {
throw new IllegalArgumentException();
}
if(root == friend) {
return false;
} else if(root.getKey() < friend.getKey()) {
if(root.getLeft() != null) {
root.setLeft(friend);
return true;
} else {
root.setLeft(node);
return true;
}
} else { if(root.getRight() != null) {
root.setRight(friend);
} else {
root.setRight(node);
return true;
}
}
return false;
}
I expect the User friend to be added to the database and output its details but the output that I am currently getting is null.
You don't define "root" in your method, therefore it's always null. You should define "root" to compare with friend and getting any data from it.

SonarQube Refactor this method to reduce its Cognitive Complexity

I have the below utility method and I am using multiple if statements and getting cognitive complexity issue. I went through some links, but I am not able to understand how should I change my code without affecting users of this method.
public static boolean isWrapperValid(WrapperClass wrapper, boolean isTechnicalToken){
String key=null;
boolean isValidWrapper = false;
if (wrapper != null && wrapper.length() > 7
&& wrapper.substring(0, 6).equalsIgnoreCase("XYZ"))
{
wrapper= wrapper.substring(7, wrapper.lastIndexOf('.')+1);
}
if(wrapper != null && wrapper.equalsIgnoreCase("TFR")) {
isValidWrapper=Boolean.TRUE;
}
try {
key = wrapper.getKey();
}
catch (Exception exception) {
return isValidWrapper;
}
if(key!=null) {
Date tokenExpiryTime = key.getExpiresAt();
if(tokenExpiryTime!=null) {
return isValidWrapper;
}
String algorithm=key.getAlgorithm();
if(!DESIRED_ALGO.equals(algorithm)) {
return isValidWrapper;
}
String value6=key.getType();
if(!DESIRED_TYPE.equals(value6)) {
return isValidWrapper;
}
if(key.getValue1()!=null && key.getValue2().size()>0 && key.getValue3()!=null && key.getValue4()!=null && key.getValue5()!=null) {
isValidWrapper=Boolean.TRUE;
}
}
return isValidWrapper;
}
Please share your suggestions to refactor this code.
I don't think that merging many if conditions to one or simply do a code clean up, for example by changing the order of some instructions, can solve your problem.
Your code does not match the single responsibility principle. You should refactor this big method to smaller parts. Due to this it will testable, easier to maintain and read. I spent some time and did this:
public static boolean isWrapperValid(WrapperClass wrapper, boolean isTechnicalToken) {
final WrapperClass unpackedWrapper = unpackWrapper(wrapper);
boolean wrapperValid = isUnpackedWrapperValid(unpackedWrapper);
Key key = null;
try {
key = unpackedWrapper.getKey();
} catch (final Exception exception) {
return wrapperValid;
}
if (key != null) {
if (doesKeyMeetsBasicConditions(key)) {
return wrapperValid;
}
if (doesKeyMeetsValueConditions(key)) {
return true;
}
}
return wrapperValid;
}
protected static WrapperClass unpackWrapper(final WrapperClass wrapper) {
if (wrapper != null && wrapper.length() > 7 && wrapper.substring(0, 6).equalsIgnoreCase("XYZ")) {
return wrapper.substring(7, wrapper.lastIndexOf('.') + 1);
}
return wrapper;
}
protected static boolean isUnpackedWrapperValid(final WrapperClass wrapper) {
return wrapper != null && wrapper.equalsIgnoreCase("TFR");
}
protected static boolean doesKeyMeetsBasicConditions(final Key key) {
Date tokenExpiryTime = key.getExpiresAt();
if (tokenExpiryTime != null) {
return true;
}
String algorithm = key.getAlgorithm();
if (!DESIRED_ALGO.equals(algorithm)) {
return true;
}
String value6 = key.getType();
return !DESIRED_TYPE.equals(value6);
}
protected static boolean doesKeyMeetsValueConditions(final Key key) {
return key.getValue1() != null && key.getValue2().size() > 0
&& key.getValue3() != null && key.getValue4() != null
&& key.getValue5() != null;
}
I don't know the domain logic, so some of my methods have stupid names etc. As you can see, now you have a lot of smaller methods with not many branches (if conditions) - easier to test (a static code is not nice, but you can mock it by using for example PowerMock).
A bit of rewriting delivered a simplification, that still could be improved upon.
public static boolean isWrapperValid(WrapperClass wrapper, boolean isTechnicalToken){
if (wrapper != null && wrapper.length() > 7
&& wrapper.substring(0, 6).equalsIgnoreCase("XYZ"))
{
wrapper = wrapper.substring(7, wrapper.lastIndexOf('.')+1);
}
boolean isValidWrapper = wrapper != null && wrapper.equalsIgnoreCase("TFR");
try {
String key = wrapper.getKey();
if (key != null && key.getExpiresAt() == null
&& DESIRED_ALGO.equals(key.getAlgorithm())
&& DESIRED_TYPE.equals(key.getType())
&& key.getValue1() != null && !key.getValue2().isEmpty()
&& key.getValue3() != null && key.getValue4() != null
&& key.getValue5() != null) {
isValidWrapper = true;
}
}
catch (Exception exception) {
// DO NOTHING
}
return isValidWrapper;
}
After comment: here I catch any exception for all calls.
First of all, Sonar should give you more flags: reusing the wrapper parameter is usually a bad practice, NPE where invoking wrapper.getKey because wrapper can be null, but anyway, not the point...
Try reducing the number of if statements by creating local boolean variables (or possibly 1 big if statement if you have less than 5 or 6 tests, but often less readable). Once it's done, you should only have 1 block testing these boolean variables, and have one return statement, like the example above (not necessarily accurate!):
boolean expired = tokenExpiryTime != null;
boolean desiredAlgo = DESIRED_ALGO.equals(key.getAlgorithm());
boolean desiredType = DESIRED_TYPE.equals(value6);
if (expired || !desiredAlgo || !desiredType) {
return isValidWrapper;
}
However, your Cognitive complexity level seems pretty low if this kind of algorithm triggers it...
Another big way to reduce an algorithm complexity is to turn sub-blocks of code (loops, if and try-catch) into private methods. In your example, it could be something like a checkWrapperValidity method, responsible for every test returning isValidWrapper

Java - how to return to a parent method?

I'm working on a method which should check in a guest to a room if the password matches. The method should also return that room.
public Room checkIn(String password, String guestName) {
assert (guestName != null);
if (this.password.testWord(password) && roomList.stream().allMatch(r -> r.getGuest().getName() != guestName)) {
roomList.forEach(r -> {
if (r.getGuest() == null) {
new Guest(guestName).checkin(r);
return r;
}
});
}
return null;
}
Eclipse gives me an error about returning within the forEach() method, since forEach() shouldn't return anything. I'm trying to have the checkIn() method return the room. Is there any way I can do this?
Use Stream.findFirst() to get the first matching element:
Optional<Room> r = roomList.stream().filter(r -> r.getGuest() == null).findFirst();
if (r.isPresent()) {
new Guest(guestName).checkin(r.get());
return r.get();
}

In Java, how should I declare the return type if a recursive method can return mixed values?

I have the following method definition which is intended to search a JSON object for a given key and return either the JSONObject or the String value of that key. To ensure it searches through every level of the JSON object I have made it recursive, but only in the event that a deeper JSONObject can be returned. The compiler complains that this must return an Object because I have declared that return type. Fine. In two cases I am returning an object but I think its problem is that in some circumstances it will not return anything. If I add a final return false, or something, it will pass the compiler check but a call to this method will always then (eventually) return false making it useless. I am not used to a strictly typed language like Java so I haven't encountered a similar issue before. Any pointers would be appreciated.
public Object find(String contentId, JSONObject node) {
JSONObject currentNode = (node != null) ? node : this.txtContent;
Iterator<?> nodeKeys = currentNode.keys();
while ( nodeKeys.hasNext() ){
try {
String key = (String) nodeKeys.next();
if (key.equals(contentId)) {
if (currentNode.get(key) instanceof JSONObject) {
return currentNode.getJSONObject(key);
} else {
return currentNode.getString(key);
}
} else if (currentNode.get(key) instanceof JSONObject) {
find(contentId, currentNode.getJSONObject(key));
}
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
}
Let's see, you should use the value returned by the find call and return null if not found:
public Object find(String contentId, JSONObject node) {
JSONObject currentNode = (node != null) ? node : this.txtContent;
Iterator<?> nodeKeys = currentNode.keys();
while ( nodeKeys.hasNext() ){
try {
String key = (String) nodeKeys.next();
if (key.equals(contentId)) {
if (currentNode.get(key) instanceof JSONObject) {
return currentNode.getJSONObject(key);
} else {
return currentNode.getString(key);
}
} else if (currentNode.get(key) instanceof JSONObject) {
Object foundObj = find(contentId, currentNode.getJSONObject(key));
if (foundObj!=null) {
return foundObj;
}
}
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
return null;
}
The Either class was made for situations just like this. See the documentation here
Usage:
Either<OneResultType,OtherResultType> result;
This avoids expensive instanceOf checks. Return null if the object is not found.
add return null; below the while loop
This method would only keep returning false if it kept hitting the else if constantly until the while loop condition ends and you get to your "return false".
Instead of return false have return null; at the very end and in the calling method have a check to see if the returned object was null which means nothing was found

Categories