How to replace/transform/expand String in java - java

I have a method which maps a given string to another string like if the input to the method is "RS256" it will return "SHA256WithRSA" and many more. My method is given below
public String getAlgorithm(String alg) {
// The internal crypto provider uses different alg names
switch(alg) {
case "RSA256" : return "SHA256withRSA";
case "SHA384" : return "SHA384withRSA";
case "SHA512" : return "SHA512withRSA";
}
throw new Exception("Not supported");
}
is there any other way to do this (i don't want to use MAP). I'm looking to see if there is any design pattern or any OOP concept to do this.

Use real map, I mean java.util.Map which keeps key-value pair ex. Map<Key,Value>
Map<String,String> map= new HashMap<String,String>();
map.add("RSA256","SHA256withRSA");
map.add("SHA384","SHA384withRSA");
map.add("SHA512","SHA512withRSA");
...
public String getAlgorithm(String alg) {
return map.get(alg);
}

You are actually written a Facade Pattern here, I think you are wrapping some kind of library. switch-case statement should be fine.
Using map introduces overhead, so better no to use it.

You can use if-else to check alg equals to your condition and return value similar to this. But current way is very similar to this.
Why you can't use Map? that is the better way.
Map<String,String> algoMap=new HashMap<>(String,String);
Now you can put algoMap.put("algoName","Value")

Use HashMap
HashMap<String, String> newMap = new HashMap<String, String>();
newMap.put("RSA256", "SHA256withRSA");
newMap.put("SHA384", "SHA384withRSA");
newMap.put("SHA512", "SHA512withRSA");
String value = (String) newMap.get("RS256");

You can use enum types as well, but either way you have to use a switch statement without maps.
enum Algorithm {
RSA256,
SHA384,
SHA512;
public String name(String pValue) throws Exception {
switch(this) {
case RSA256:
return "SHA256withRSA";
case SHA384:
return "SHA384withRSA";
case SHA512:
return "SHA512withRSA";
default:
throw new Exception("Not supported");
}
}
}

Related

Extract all True properties and add to a list

I have a java class with 3 boolean property like this
boolean isActive;
boolean isEnable;
boolean isNew;
every property is related to an enum (e.g. ACTIVE,ENABLE,NEW).
I want to have 2 lists of enum. One which has only the enums related to true property value and one for the false one.
just to be clear. using if-else statement I could have
Set<FlagEnum> flagSet = new HashSet<>();
Set<FlagEnum> falseFlagSet = new HashSet<>();
if (object.isActive()) {
flagSet.add(ACTIVE);
} else {
falseFlagSet.add(ACTIVE);
}
if (object.isEnable()) {
flagSet.add(ENABLE);
} else {
falseFlagSet.add(ENABLE);
}
if (object.isNew()) {
flagSet.add(NEW);
} else {
falseFlagSet.add(NEW);
}
is there a way to avoid all these if-else?
I tried with something like
Map<boolean, List<Pair<boolean, FlagEnum>>> res = Stream.of(
new Pair<>(object.isActive(), ACTIVE),
new Pair<>(object.isNew(), NEW),
new Pair<>(object.isEnable(), ENABLE))
.collect(Collectors.partitioningBy(Pair::getKey));
but the resulted structure is an additional complexity which I would like to avoid.
In my real case, I have more than 15 boolean properties...
You can simplify this in various ways. Which of them make sense, depends on your exact requirements.
You can derive the falseFlagSet trivially from the flagSet using EnumSet.complementOf after populating the flagSet:
EnumSet<FlagEnum> falseFlagSet = EnumSet.complementOf(flagSet);
This assumes that all FlagEnum values have corresponding flags. If that's not the case then you need to construct a EnumSet with all enums that have flags and subtract flagSet from that using removeAll.
#1 already removes the need for the else in your cascade, simplifying the code to
if (object.isActive()) {
flagSet.add(ACTIVE);
}
if (object.isEnable()) {
flagSet.add(ENABLE);
}
if (object.isNew()) {
flagSet.add(NEW);
}
If you have enough different flags, then you can create a mapping from getter method to FlagEnum value like this:
Map<Function<YourClass,Boolean>,FlagEnum> GETTERS = Map.of(
YourClass::isActive, FlagEnum.ACTIVE,
YourClass::isNew, FlagEnum.NEW,
YourClass::isEnable, FlagEnum.ENABLE);
Then you can use this to make the whole process data-driven:
EnumSet<FlagEnum> getFlagSet(YourClass yourObject) {
EnumSet<FlagEnum> result = EnumSet.noneOf(FlagEnum.class);
for (Map.Entry<Function<YourClass,Boolean>, FlagEnum> getter : GETTERS.entrySet()) {
if (getter.getKey().apply(yourObject)) {
result.add(getter.getValue());
}
}
return result;
}
If the number of flags is very big, then you could switch entirely to reflection and detect the flags and matching getters dynamically using string comparison, but I would not suggest that approach. If you need something like that then you probably should switch to a framework that supports that kind of feature and not implement it yourself.
That last two obviously only makes sense when the number of flags is big. If it's actually just 3 flags, then I wouldn't mind and just have 3 simple if statements.
As a slight tangent: GETTERS above should definitely be an immutable map (wrap it in Collections.unmodifiableMap or use something like Guava ImmutableMap) and it could be argued that the same applies to the return value of the getFlagSet method. I've left those out for succinctness.
You can use a private helper method for this.
private void addFlagSet(boolean condition, FlagEnum flagEnum,
Set<FlagEnum> flagSet, Set<FlagEnum> falseFlagSet) {
Set<FlagEnum> chosenFlagSet = condition ? flagSet: falseFlagSet;
chosenFlagSet.add(flagEnum);
}
Call it as:
addFlagSet(object.isActive(), FlagEnum.ACIVE, flagSet, falseFlagSet);
addFlagSet(object.isNew(), FlagEnum.NEW, flagSet, falseFlagSet);
addFlagSet(object.isEnable(), FlagEnum.ENABLE, flagSet, falseFlagSet);
You could probably use Reflection to get all methods, then check if a getReturnType() == boolean.class. Problem is the connection between the method's name and the enum. If every single one is named like the method without the 'is', you could use FlagEnum.valueOf() to retrieve the enum value from the method name and use it.
I think this could be the easiest and clearest way to do what I need
Map<Boolean, Set<FlagEnum>> flagMap = new HashMap<>();
flagMap.computeIfAbsent(object.isActive(), h -> new HashSet()).add(ACTIVE);
flagMap.computeIfAbsent(object.isEnabled(), h -> new HashSet()).add(ENABLE);
flagMap.computeIfAbsent(object.isNew(), h -> new HashSet()).add(NEW);
//to get TRUE set simply :
flagMap.get(true);
what do you think?

if statements alternative with Java 8

Have a function like this:
public void toDo(Req req){
if(req.getSection().equals("A")) {
return execA(req);
}
if(req.getSection().equals("B")) {
return execB(req);
}
if(req.getSection().equals("N")) {
return execN(req);
}
}
How can I simplify it? The general idea, how to exclude if statements for the identification type of function - Strings - A, B, N. Any solutions with Java 8 like pattern matching with Scala?
Can't you use just a simple switch?
switch (req.getSection()){
case "A" : execA(req); break;
case "B" : execB(req); break;
case "N" : execN(req); break;
default: break;
}
Besides the switch solution, which works for strings and int values, you can use a Map:
Map<String,Consumer<Req>> handlers;
{
handlers.put("A", req -> execA(req));
handlers.put("B", req -> execB(req));
handlers.put("N", req -> execN(req));
}
Consumer<Req> defaultBehavior=req-> {
throw new IllegalArgumentException(req.getSection());
};
public void toDo(Req req) {
handlers.getOrDefault(req.getSection(), defaultBehavior).accept(req);
}
Besides supporting other key types, it allows to assemble the map at runtime, e.g. using handlers provided by different, perhaps dynamically loaded, modules, etc.
Using reflection and the array of methods you have on your class, you could apply a filter (if-replacement), mapping (to return value) and optionally defining a default value (orElse).
This approach might be good, if either the number of cases gets huge or dynamic. But for your particular case, I think it's overkill. Better stick to the switch-case solution.
public Optional<Object> toDo(Req req) {
return Stream.of(this.getClass().getMethods())
.filter(m -> m.getName().equals("exec" + req.getSection()))
.map(this::invokeUnchecked).findFirst();
}
private Object invokeUnchecked(final Method m) {
try {
return m.invoke(this);
} catch (IllegalAccessException| InvocationTargetException e) {
throw new RuntimeException(e);
}
}
In case you don't want to use an optional, you have to declare a default with .findFirst().orElse(() -> ...)

Design pattern for long if null statements for POJO object

I'm looking for a design pattern or even advice on some code that I saw the other day. The general structure is this (pseudo code):
public String getUrl(){
Person person= new Person();
StringBuilder builder = new StringBuilder();
if(person.getName() != null){
builder.append(",_name=");
builder.append(person.getName());
}
if(person.getLastName() != null){
builder.append(",_lastName=");
builder.append(person.getName());
}
if(person.getPostCode() != null){
builder.append(",_postCode=");
builder.append(person.getPostCode());
}
// So on and so forth
return builder.toString();
}
Now the problem is that I don't have control over Person class (I'm just given it via an API call). I was thinking to use reflection and a map like so:
Map<String, String> methodNameToUrlParameter; //Pre Build this map with method name and the actual parameter key
Map<String, String> urlParameterToValue;
Method[] methods = person.getMethods();
for(Method method: methods ){
String result = (String) method.invoke(person, null);
if(result != null){
String urlParam = methodNameToUrlParameter.get(method.getName());
urlToValue.put(urlParam, result );
}
}
Then I can go on my merry way. But this doesn't seem too great to me and I don't really know all too much about reflection, any ideas? Remember, I have no control over the Person class and it just has getters since it's immutable.
Thanks.
Edit:
What I am asking is there a better way to represent the flow of logic here with out using a too many if statements that do null checks. Perhaps a design pattern that I do not know about.
2nd Edit:
There's maybe like 20 if-null checks, which made things ugly. Is there a way todo it without none?
Use either Apache Commons ToStringBuilder or Guava's MoreObjects.ToStringHelper. Or get inspired by them.
For a minor change with better readability, you could pull the redundant code into its own method:
void AddField(StringBuilder builder, String value, String fieldName) {
if (value != null) {
builder.append(",_");
builder.append(fieldName);
builder.append("=");
builder.append(value);
}
}
which would simplify your code sample to the following:
public String getUrl(){
Person person= new Person();
StringBuilder builder = new StringBuilder();
AddField(builder, person.getName(), "name");
AddField(builder, person.getLastName(), "lastName");
AddField(builder, person.getPostCode(), "postCode");
// So on and so forth
return builder.toString();
}

Hashmap keys will not work

I have a HashMap which certain keys like "crash" and "crashes" which return the same response. I want to create a new HashMap that maps synonyms to a unique key in the responseMap (for example, map "crash", "crashes" and "crashed" to "crash" in the synonymMap).
private void fillSynonymMap()
{
synonymMap.put("crash", "crash");
synonymMap.put("crashes", "crash");
synonymMap.put("crashed", "crash");
}
What I am stuck on is how to input these keys so that I can simplify the code below.
private void fillResponseMap()
{
responseMap.put("crash",
"Well, it never crashes on our system. It must have something\n" +
"to do with your system. Tell me more about your configuration.");
responseMap.put("crashes",
"Well, it never crashes on our system. It must have something\n" +
"to do with your system. Tell me more about your configuration.");\
responseMap.put("crashed",
"Well, it never crashes on our system. It must have something\n" +
"to do with your system. Tell me more about your configuration.");
}
public String generateResponse(HashSet<String> words)
{
for (String word : words) {
String response = responseMap.get(word);
if(response != null) {
return response;
}
}
// If we get here, none of the words from the input line was recognized.
// In this case we pick one of our default responses (what we say when
// we cannot think of anything else to say...)
return pickDefaultResponse();
}
After a little messing about I wrote a function that will look for a synonym, before returning a default message.
public String getResponse()
{
HashMap<String, String> responseMap = new HashMap<String, String>();
HashMap<String, String> synonymMap = new HashMap<String, String>();
responseMap.put("crash", "Hello there");
// Load the response value.
synonymMap.put("crash", "crash");
synonymMap.put("crashed", "crash");
synonymMap.put("crashes", "crash");
// Load the synonyms.
String input = "crashed";
// Select input value.
if(responseMap.containsKey(input))
{
// Response is already mapped to the word.
return responseMap.get(input);
}
else
{
// Look for a synonym of the word.
String synonym = synonymMap.get(input);
if(!synonym.equals(input) && responseMap.containsKey(synonym))
{
// If a new value has been found that is a key..
return responseMap.get(synonym);
}
}
// If no response, set default response.
input = "This is a default response";
return input;
}
As you can see the function first checks if the key exists. If it doesn't, it attempts a synonym. If that synonym doesn't pass the test, it will move to the default code at the bottom, which will set input to some default value and return that instead :)
You could use a second map.
The first map translates the synonyms to the basic key, which in turn can be used for the second map with the answers.
This also allows flexible extension of synonyms without enlarging the actual response map.
Besides, in this case you can actually use another type as key for the answser map. It just has to be same as the value type of synonyms maps.
That way, you could also use
Map<String, YourEnum> and Map<YourEnum, String>
with EnumMap as implementation of the Map interface.

Java CompareToIgnoreCase

im creating a method where a user input has to type A/B to get a return. how do i make my code case insensitive to make it work?
String examcode (String code) {
if (code.compareToIgnoreCase("A")) {
EXAM_NAME = "Subject A";
}
else if (code.compareToIgnoreCase("B")) {
EXAM_NAME = "Subject B";
}
else {
EXAM_NAME = "no code";
}
return EXAM_NAME;
}
Use equalsIgnoreCase(), not compareToIgnoreCase().
if (code.equalsIgnoreCase("A")) {
EXAM_NAME = "Subject A";
} //...
If you want to use compareToIgnoreCase() to check equality, you need to compare the result to 0:
if (code.compareToIgnoreCase("A") == 0) {
//...
just like any other compareTo method. But there's no advantage to using it here.
Edit:
An alternative to your entire approach might be to use a case-insensitive map instead. Something like this:
Map<String, String> subjects = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
subjects.put("A", "Subject A");
subjects.put("B", "Subject B");
//...
String subjectName = subjects.get(code);
if ( subjectName == null ) {
subjectName = "no code";
}
Or, you could also use a normal case-sensitive map and just convert all keys to lower case before doing map operations.
Just use the method -
String.equalsIgnoreCase(java.lang.String) which returns a boolean and does the job for what you are looking for.
if (code.compareToIgnoreCase("A")) is not valid since compareToIgnoreCase returns int.
Reading the javadoc for String would have provided your answer for you. Google would have turned that right up.
Use code.equalsIgnoreCase("your string") which returns a boolean value, OR
use code.compareToIgnoreCase("your string") == 0. compareToIgnoreCase gives you a way to determine the "order" of two strings. Again, enjoy the javadoc.
Use same code but equalsIgnoreCase(String) instead of compareToIgnoreCase(String).
What you want is String#equalsIgnoreCase(String) which returns a boolean.
use String.toLowerCase() (or String.toUpperCase()) before comparing.
if (code.toLowerCase().equals("a")) {
EXAM_NAME = "Subject A";
}
Note that like all string methods, code.toLowerCase does not change the string stored in 'code', but returns a copy of 'code's value all in lower case.

Categories

Resources