Refactor multiple cases from switch - java

TestDTO testDTO = new TestDTO();
for (Object attribute : row.getAttributes()) {
switch (attribute) {
case "CATEGORY":
testDTO.setCategory((String) attribute);
break;
case "DESCRIPTION":
testDTO.setDescription((String) attribute);
break;
case "NOTE":
testDTO.setNote((String) attribute);
break;
case "FEATURES":
testDTO.setFeatures((String) attribute);
break;
case "INDICATOR":
testDTO.setIndicator((String) attribute);
break;
case "LABEL":
testDTO.setLabel((String) attribute);
break;
case "TYPE":
testDTO.setType((String) attribute);
break;
default:
}
}
As you can see in above code, we are using multiple case for setting data. Code is working fine.
Is there any way for reducing multiple cases for setting those data.
In the above code, the problem is maintainability. Because suppose if we have 30 fields, then we need to put 30 cases for that.
Is there any other way to achieve the same?

Without refactoring you cannot do anything really helping the situation. Also you will need to add specific code for every field anyway - this is obvious
In abstract situation what you could do would be to implement factory or strategy pattern and e.g. register proper handlers for every type of attribute - something like
Map<Object, BiConsumer<TestoDTO, Object>> handlers; // then you can add for example handlers.put("TYPE", (d, a) -> d.setType(a))
And just iterate over attributes
row.getAttributes().forEach(a -> handlers.get(attribute).accept(dto, a)); // ofc you need to handle all situation like NPE, no key etc
In scope of mapping objects you could use some existing tool like ObjectMapper or ModelMapper because it's quite possible that these tools will resolve your issue out of the box
Last and least (:)) solution is to use some reflection, map attribute to field name, extract setter... Don't do this :) it's filthy, insecure, hard to write and understand - will cause many issues you will regret but because it's an option I'm mentioning this

For a robust solution you can also build your association using enumerated types and method references, and conveniently encapsulate the map into a single type. Plus, it's pretty obvious how to add new fields:
enum DTOMap
{
CATEGORY(TestDTO::setCategory),
DESCRIPTION(TestDTO::setDescription);
private final BiConsumer<TestDTO, String> attributeConsumer;
private DTOMap(BiConsumer<TestDTO, String> attributeConsumer) {
this.attributeConsumer = attributeConsumer;
}
public static void execute(TestDTO testDTO, Object attribute) {
String attributeAsString = (String) attribute;
DTOMap.valueOf(attributeAsString.toUpperCase()).attributeConsumer.accept(testDTO, attributeAsString);
}
}
With this your switch statement can be reduced to a single line:
for (Object attribute : row.getAttributes()) {
DTOMap.execute(testDTO, attribute);
}

You can use reflection to refactor it like below:
TestDTO testDTO = new TestDTO();
for (Object attribute : row.getAttributes()) {
Method method = testDTO.getClass().getMethod("set" + capitalize((String) attribute), String.class);
method.invoke(testDTO, (String) attribute);
}
The capitalize func:
public String capitalize(String string) {
return string.substring(0, 1).toUpperCase() + string.substring(1).toLowerCase();
}

Related

How to create reusable optional mapping with method references?

While I'm trying to use Optional features with method references, it really confused me how to optimize it with reusable code. I think I'm stuck while trying to use all those new features (for me) at the same time i decided to get rid of java-6 style, now I think i can't think simple, i feel that it gets overcomplicated. How can i create
List<BooleanExpression> expressionMapping = new ArrayList<>();
if (request != null) { // request is input parameter, a DTO
Optional.ofNullable(request.getPlantId())
.map(campaign.plant.id::contains) // campaign is static created by Querydsl
.ifPresent(expressionMapping::add);
Optional.ofNullable(request.getTitle())
.map(campaign.title::containsIgnoreCase)
.ifPresent(expressionMapping::add);
Optional.ofNullable(request.getCampaignNumber())
.map(this::getLikeWrapped)
.map(campaign.campaignNumber::like)
.ifPresent(expressionMapping::add);
... 20 more Optional bunch of code like this
}
also having trouble with writing this code with Optional like previous ones:
if (request.getLockVehicle() != null) {
if (request.getLockVehicle()) {
expressionMapping.add(campaign.lockVehicle.isNotNull());
} else {
expressionMapping.add(campaign.lockVehicle.isNull());
}
}
What about use enum to declare all fields from Request and use it as common part of the code. I did not check it, this is only to show my approach:
public enum RequestField {
PLANT_ID(Request::getPlantId, (val, campaign) -> campaign.plant.id::contains),
TITLE(Request::getTitle, (val, campaign) -> campaign.title::containsIgnoreCase),
CAMPAIGN_NUMBER(Request::getCampaignNumber, (val, campaign) -> campaign.campaignNumber::like),
// ... more fields here ...
;
private final Function<Request, Optional<Object>> get;
private final BiFunction<Object, Campaign, BooleanExpression> map;
RequestField(Function<Request, Object> get, BiFunction<Object, Campaign, BooleanExpression> map) {
this.get = get.andThen(Optional::ofNullable);
this.map = map;
}
public static List<BooleanExpression> getBooleanExpressions(Request request, Campaign campaign) {
if (request == null)
return Collections.emptyList();
List<BooleanExpression> res = new LinkedList<>();
for (RequestField field : values())
field.get.apply(request)
.map(r -> field.map.apply(r, campaign))
.ifPresent(res::add);
return res.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(res);
}
}
And your client code will be looking like:
List<BooleanExpression> booleanExpressions = RequestField.getBooleanExpressions(request, campaign);
P.S.
Your last code could be look like:
if (request.getLockVehicle() != null)
expressionMapping.add(request.getLockVehicle() ? campaign.lockVehicle.isNotNull() : campaign.lockVehicle.isNull());
The aim of using Optional is informing who is calling that method / parameter that it could be null.
In the first part of your code, you are not getting any advantage from this, you are just rewriting some code wrapping it around Optional logic but, as you said, without any "reusable" purpose.
A useful way is using it as returning value of a method: for example, if you know that your title could be null, you can refactor your getter like
public Optional<String> getTitle(){
return Optional.ofNullable(this.title); //I'm guessing the 'title' variable here
}
This will help you: every time you call getTitle() , you will know that could be null, because you are obtaining an Optional<String> instead of a String.
This will bring then you to:
request.getTitle().ifPresent(title-> title.doSomething())
// you can also add something like .orElse("anotherStringValue")
The second example could be reworked as the first one, making the return of getLockVehicle() as Optional<Boolean>, even if I suggest here setting that with a default value in your class, probably to false... Optional<Boolean> is pretty senseless imho
Hope this helps clearing your mind

How to set method name prefix in swagger codegen?

(Newbie to Swagger)
In the swagger specification file, the operationId is the name of the operation, corresponding to the HTTP methods.
For example,
"/pet/findByStatus": {
"get": {
"tags": [
"pet"
],
"summary": "Finds Pets by status",
"description": "Multiple status values can be provided with comma separated strings",
"operationId": "findPetsByStatus",
As seen above, operationId = findPetsByStatus. Suppose I want to generate a prefix for all get operations in my java code, with prefix = 'get_'.
For example, I would expect the swagger codegen to produce all operations corresponding to HTTP GET methods with a prefix = 'get_'. Specifically, above, it might generate: get_findPetsByStatus.
Is there a way to tell swagger codegen to prefix methods?
Please note that I want to use swagger-codegen itself and not APIMatic-like alternatives.
Implement AbstractJavaCodegen (or a subclass that implements it) and overload the postProcessOperations function to prepend prefixes to operations (operationId property of the CodegenOperation class). See making-your-own-codegen-modules for instructions on building and running a custom codegen.
Pseudocode:
public class MyCodegen extends AbstractJavaCodegen{ \\or
[...]
#Override
public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
super.postProcessOperations(objs);
Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
if (operations != null) {
List<CodegenOperation> ops = (List<CodegenOperation>) operations.get("operation");
for (CodegenOperation operation : ops) {
if(operation.httpMethod.equals("GET"){
operation.operationId = "get_" + operation.operationId;
}[...]
}
}
return objs;
}
}

String to String mapping using Spring?

From external system I receive String representation of some abbreviations and I have to make transformation(conversion) to another String for example:
"O" -> Open
"C" -> Closed
"E" -> Exit
For Object to Object conversion I was using Spring Custom COnverter
import org.springframework.core.convert.converter.Converter;
public class Converter<Source, Target> implements Converter<Source, Target>
public final Target convert(#Nonnull Source source) {
...
}
But I can't create String to String converter. I do not want to use external mapping library only Spring capabilities. But I can't do this. The simplest thing that I can do is switch
String input = "O";
String result = null;
switch(input){
case "O": result ="Open"
break;
case "C": result ="Close"
break;
....
In matter of fact I have to do over 100 mapings. Can Spring offer better solution?
When you don't have any logic to execute in switch-case, you can use a static HashMap<String,String>
static HashMap<String,String> map = new HashMap<>();
static
{
map.put("O","Open");
map.put("C","Close");
.....................
}
Instead of switch-case just use
map.get(input);
If you are suing Java 8, you can even use
map.getOrDefault(input,"");

Multiple if conditions ,how to optimize it

i am working on a large application which has differnt conditions(ifs) and different methods associated with it.Please suggest a way to optimize below mentioned code(reduce as much of nested ifs as possible).I would like the code to able incorporate any other specific condition with ease.(I use property files to fetch conditions)
.
public getParameter(String parameter)
{
if(parameter=specific condition1
||parameter=specific condition2)
{
do this
}
if(parameter=specific condition3)
{
do something else
}
if(parameter=specific condition4)
{
do something else
}
if(parameter=general condition)
{
do something else
}
else {
do something else
}
Say you have a property file with
do1=val1,val2,val3
do2=val5,val6,val7
(it seems you have a fixed set of actions)
You may load it with
HashMap<String, HashSet<String>> rules = new HashMap<String, HashSet<String>>();
for(String key : properties.stringPropertyNames()) {
HashSet<String> set = new HashSet<String>();
set.addAll(Arrays.asList(properties.getProperty(key).split(",")));
rules.put(key, set);
}
Now you have a map linking action names ("do1", etc.) to sets of possible values ("val1", etc.).
You may execute the rules with
if (rules.get("do1").contains(parameter)) do1();
if (rules.get("do2").contains(parameter)) do2();
(I let you add the necessary checks to avoid null pointer exceptions for example)
you could use a switch case.
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html

How to convert my state machine to java?

Here is the normal way I would do things in C++:
class object
{
public:
enum
{
STATE_ACTIVE = 0,
STATE_INACTIVE,
OBJ_NUM_STATES,
}
int m_State;
virtual void UpdateState ()
{
switch(this->m_state)
{
case STATE_ACTIVE: /* do stuff*/ break;
case STATE_INACTIVE: /* do stuff*/ break;
}
}
}
class SpecialGameObject : public Object
{
public:
enum
{
STATE_SPECIAL_A = OBJ_NUM_STATES + 1,
STATE_SPECIAL_B,
SPECIAL_NUM_STATES,
}
virtual void UpdateState ()
{
Object::UpdateState();
switch(this->m_State)
{
case STATE_ACTIVE: /* do extra stuff */ break;
case STATE_SPECIAL_A: /* do special stuff*/ break;
case STATE_SPECIAL_B: /* do special stuff*/ break;
}
}
}
I am trying to figure out to get all of this functionality to work in java. Specifically I need working:
1) Ability for derived classes to have state values that automatically line up after the derived state values. That way I can add new state values to the base class without worrying about them overlapping the rage of state values used in any of the derived classes.
2) Ability to use the state values as cases in switch statements.
I looked into using static final ints to implement my state values. But those can't be used as case statements. Then I looked into extending enums, but that isn't allowed.
Does anyone have any suggestions for me?
Thank you
You need to implement the state pattern in Java. This might help you. Wikipedia also has a simple and easy to understand example in Java.
Is this enough to get you going?
final class GameObject {
enum State { ACTIVE, INACTIVE };
State state;
void updateState()
{
switch(state) {
case ACTIVE :
// update state
break;
case INACTIVE:
// update STATE
break;
default:
assert false : "never get here";
}
}
}
Note that in Java, enums are final so you can't extend an enum directly. (Reference this SO question.) If you really need to extend the notion of state into specialized subclasses, things are probably complicated enough that you should consider using polymorphism rather than switch statements (see also here) to get what you want. Alternatively, you could bundle the "super" state with specialized substates in a wrapper super- and sub-classes, perhaps with defined interfaces.
And, if you want to get seriously warped, you could do something like this. It's very cool that Java enums can implement interfaces, but I think this counts as a particularly ugly way of using that feature for your question...
final class GameObject {
ActiveStateful state;
interface ActiveStateful {
State activeState();
}
enum State implements ActiveStateful {
ACTIVE, INACTIVE;
public State activeState() {
return this;
}
};
enum SubState implements ActiveStateful {
SPECIAL_A(State.ACTIVE), SPECIAL_B(State.ACTIVE);
SubState(final State activeState) {
this.activeState = activeState;
}
final State activeState;
public State activeState() {
return activeState;
}
}
}
But those can't be used as case statements.
If I told you this was incorrect, that would solve your problems, yes? This is incorrect: you can switch on static final int constants.
I'd recommend using an enum and its ordinal values for switch statements. That's what enum was born for.
Please consider getting rid of switch altogether. It is a horrible abomination that should have ceased decades ago but didn’t. Read the excellent “Abandoning switch In Three (And A Bit) Steps” article for more information.

Categories