How to convert one enum to another enum in java? - java

I have;
public enum Detailed {
PASSED, INPROCESS, ERROR1, ERROR2, ERROR3;
}
and need to convert it to the following;
public enum Simple {
DONE, RUNNING, ERROR;
}
So first PASSED->DONE and INPROCESS->RUNNING, but all errors should be: ERROR. Obviously it is possible to write cases for all values, but there may be a better solution?

Personally I would just create a Map<Detailed, Simple> and do it explicitly - or even use a switch statement, potentially.
Another alternative would be to pass the mapping into the constructor - you could only do it one way round, of course:
public enum Detailed {
PASSED(Simple.DONE),
INPROCESS(Simple.RUNNING),
ERROR1(Simple.ERROR),
ERROR2(Simple.ERROR),
ERROR3(Simple.ERROR);
private final Simple simple;
private Detailed(Simple simple) {
this.simple = simple;
}
public Simple toSimple() {
return simple;
}
}
(I find this simpler than Ted's approach of using polymorphism, as we're not really trying to provide different behaviour - just a different simple mapping.)
While you could potentially do something cunning with the ordinal value, it would be much less obvious, and take more code - I don't think there'd be any benefit.

One way is to define a method asSimple() in your Detailed enum:
public enum Detailed {
PASSED {
#Override
Simple asSimple() {
return DONE;
}
},
INPROCESS {
#Override
Simple asSimple() {
return RUNNING;
}
},
ERROR1,
ERROR2,
ERROR3;
public Simple asSimple() {
return Simple.ERROR; // default mapping
}
}
You can then simply call the method when you want to do the mapping:
Detailed code = . . .
Simple simpleCode = code.asSimple();
It has the advantage of putting the knowledge of the mapping with the Detailed enum (where perhaps it belongs). It has the disadvantage of having knowledge of Simple mixed in with the code for Detailed. This may or may not be a bad thing, depending on your system architecture.

Use EnumMap
I decouple my external xml interface from my internal domain model by implementing a transformation service. This includes mapping enums from jaxb generated code to domain model enums.
Using a static EnumMap encapsulates the concern of transformation within the class responsible for transformation. Its cohesive.
#Service
public class XmlTransformer {
private static final Map<demo.xml.Sense, Constraint.Sense> xmlSenseToSense;
static {
xmlSenseToSense = new EnumMap<demo.xml.Sense, Constraint.Sense> (
demo.xml.Sense.class);
xmlSenseToSense.put(demo.xml.planningInterval.Sense.EQUALS,
Constraint.Sense.EQUALS);
xmlSenseToSense.put(demo.xml.planningInterval.Sense.GREATER_THAN_OR_EQUALS,
Constraint.Sense.GREATER_THAN_OR_EQUALS);
xmlSenseToSense.put(demo.xml.planningInterval.Sense.LESS_THAN_OR_EQUALS,
Constraint.Sense.LESS_THAN_OR_EQUALS);
}
...
}

Guava's Enums.getIfPresent() on Enum.name()
Our case was a particular specialization of this one. We do have two Enum: one we use in the application and another one we use in the core library. The core library is used by a handful of applications, by different teams. Each application views a subset of the whole functionality. The whole functionality is configured with the enums in order to switch on and off, throttle up or down, select strategies, etc.
So we ended up with:
one enum for the library, containing all the possible configurations, visible from the applications and also some library-specific
one enum for each application, containing the literals corresponding to what the application can see/touch in the library, and some application-specific
Then as we pass data down to the library, we adapt all data and also those configurations. We own all enums, so we can choose to call the same configuration with the same literal in different enums.
Enum LibraryConfig {
FUNCTION_ONE,
FUNCTION_TWO,
FUNCTION_THREE,
FUNCTION_FOUR;
}
Enum Aplication1Config {
FUNCTION_ONE,
FUNCTION_TWO,
FUNCTION_THREE,
APPL1_FUNCTION_ONE,
APPL1_FUNCTION_TWO;
}
Enum Aplication2Config {
FUNCTION_ONE,
FUNCTION_TWO,
FUNCTION_FOUR;
APPL2_FUNCTION_ONE;
}
When we need to convert from one type to another (app --> lib or lib --> app) we use the getIfPresent() method from com.google.common.base.Enums in this way:
Aplication1Config config1App1 = FUNCTION_TWO;
LibraryConfig configLib = Enums.getIfPresent(LibraryConfig.class, config1App1.name()).orNull();
We check configLib for null value to see if there was successful conversion. This last step we use because of the APPX_FUNCTION_YYY, which are application-specific, and for the conversion on the direction lib --> app, not to pass configuration values library-specific (FUNCTION_FOUR in the example).
maven's dependency management:
Just in case anyone needs it:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>
Home grown version:
You can make your own conversion using the Enum methods, but you have to take care of the exception to detect when the conversion did not succeed:
try {
Aplication1Config config1App1 = FUNCTION_TWO;
LibraryConfig configLib = LibraryConfig.valueOf(config1App1.name());
} catch (IllegalArgumentException iae) {
// if the conversion did not succeed
}

Ted's answer is very Javaly, but the expression
passed == PASSED ? DONE : ERROR
would do the job, too.

To me that sounds more like a conceptual problem than a programming problem. Why don't you just remove the "Simple" enum type and use the other one instead in all places in the program?
Just to make that more clear with another example: Would you really try to define an enum type for the work days in a week (Monday to Friday) and another enum for all days of a week (Monday to Sunday)?

Here is the simple enum mapper with test:
-- IMPLEMENTATION
-- ENUMS
public enum FirstEnum {
A(0), B(1);
private final int value;
private FirstEnum(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
public enum SecondEnum {
C(0), D(1);
private final int valueId;
private SecondEnum(int valueId) {
this.valueId = valueId;
}
public int getValueId() {
return valueId;
}
}
--MAPPER
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.Validate;
import com.google.common.collect.Sets;
public class EnumPropertyMapping {
private final Map<?, ?> firstMap;
private final Map<?, ?> secondMap;
private final Class<?> firstType;
private final Class<?> secondType;
private EnumPropertyMapping(
Map<?, ?> firstMap, Map<?, ?> secondMap, Class<?> firstType, Class<?> secondType) {
this.firstMap = firstMap;
this.secondMap = secondMap;
this.firstType = firstType;
this.secondType = secondType;
}
public static Builder builder() {
return new Builder();
}
#SuppressWarnings("unchecked")
public <R> R getCorrespondingEnum(Object mappedEnum) {
Validate.notNull(mappedEnum, "Enum must not be NULL");
Validate.isInstanceOf(Enum.class, mappedEnum, "Parameter must be an Enum");
if (firstType.equals(mappedEnum.getClass())) {
return (R) firstMap.get(mappedEnum);
}
if (secondType.equals(mappedEnum.getClass())) {
return (R) secondMap.get(mappedEnum);
}
throw new IllegalArgumentException("Didn't found mapping for enum value: " + mappedEnum);
}
public static class Builder {
private final Map<Object, Object> firstEnumMap = new HashMap<>();
private final Map<Object, Object> secondEnumMap = new HashMap<>();
private Class<?> firstEnumType;
private Class<?> secondEnumType;
public <T extends Enum<T>> Builder addFirst(Class<T> enumType, String propertyName) {
firstEnumType = enumType;
initMap(firstEnumMap, enumType.getEnumConstants(), propertyName);
return this;
}
public <T extends Enum<T>> Builder addSecond(Class<T> enumType, String propertyName) {
secondEnumType = enumType;
initMap(secondEnumMap, enumType.getEnumConstants(), propertyName);
return this;
}
private void initMap(Map<Object, Object> enumMap, Object[] enumConstants, String propertyName) {
try {
for (Object constant : enumConstants) {
enumMap.put(PropertyUtils.getProperty(constant, propertyName), constant);
}
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException ex) {
throw new IllegalStateException(ex);
}
}
public EnumPropertyMapping mapEnums() {
Validate.isTrue(firstEnumMap.size() == secondEnumMap.size());
Validate.isTrue(Sets.difference(firstEnumMap.keySet(), secondEnumMap.keySet()).isEmpty());
Map<Object, Object> mapA = new HashMap<>();
Map<Object, Object> mapB = new HashMap<>();
for (Map.Entry<Object, Object> obj : firstEnumMap.entrySet()) {
Object secondMapVal = secondEnumMap.get(obj.getKey());
mapA.put(obj.getValue(), secondMapVal);
mapB.put(secondMapVal, obj.getValue());
}
return new EnumPropertyMapping(mapA, mapB, firstEnumType, secondEnumType);
}
}
}
-- TEST
import org.junit.Test;
import com.bondarenko.common.utils.lang.enums.FirstEnum;
import com.bondarenko.common.utils.lang.enums.SecondEnum;
import static junit.framework.TestCase.assertEquals;
public class EnumPropertyMappingTest {
#Test
public void testGetMappedEnum() {
EnumPropertyMapping mapping = EnumPropertyMapping.builder()
.addSecond(SecondEnum.class, "valueId")
.addFirst(FirstEnum.class, "value")
.mapEnums();
assertEquals(SecondEnum.D, mapping.getCorrespondingEnum(FirstEnum.B));
assertEquals(FirstEnum.A, mapping.getCorrespondingEnum(SecondEnum.C));
}
}

Related

Is this possible to generically convert enum of the same type from different classes in java?

I have an external model with about 20 classes, which I have to use, but cannot modify (in code below examples: FirstExtClass, SecondExtClass). In each of these classes there is an enum, which is its internal class (code below: TheSameEnum). I am translating it into my model, in which I want each of these enums to be just one type: EnumFromMyModel. I have solved it using many functions, that convert external enums to my enums (2 examples are below, but to completely convert them I need 20 copy-paste methods like below.
I am trying to create one generic function, that would take a class with TheSameEnum as parameter and return EnumFromMyModel (something like third function in code below).
private static EnumFromMyModel
convertFirstEnumFromExternalModelToEnumFromMyModel(FirstExtClass.TheSameEnum input) {
return input.equals(FirstExtClass.TheSameEnum.FIRST_VALUE) ?
EnumFromMyModel.FIRST_VALUE :
EnumFromMyModel.SECOND_VALUE;
}
private static EnumFromMyModel convertSecondEnumFromExternalModelToEnumFromMyModel(SecondExtClass.TheSameEnum input) {
return input.equals(SecondExtClass.TheSameEnum.FIRST_VALUE) ?
EnumFromMyModel.FIRST_VALUE :
EnumFromMyModel.SECOND_VALUE;
}
private static <T> EnumFromMyModel genericConvert(T input) {
return input.equals(/*????*/) ?
ScopeUsageLimit.FIRST_VALUE :
ScopeUsageLimit.SECOND_VALUE;
}
My question is: is this possible to create such generic function?
Here is some sample code for you. You need toGeneric method.
public class App {
public static void main(String[] args) {
Generic genericFirst1 = toGeneric(Specialized1.FIRST);
Generic genericFirst2 = toGeneric(Specialized2.FIRST);
assert genericFirst1 == genericFirst2;
Specialized1 specialized1 = toSpecialized(Generic.SECOND, Specialized1.class);
assert specialized1 == Specialized1.SECOND;
}
private static <T extends Enum<?>>T toSpecialized(Generic v, Class<T> specialized1Class) {
try {
return (T) specialized1Class.getField(v.name()).get(null);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return null;
}
private static Generic toGeneric(Enum<?> e) {
return Generic.valueOf(e.name());
}
enum Generic {
FIRST, SECOND
}
enum Specialized1 {
FIRST, SECOND
}
enum Specialized2 {
FIRST, SECOND
}
}
If I understand the question correctly, you are looking for something like the below code:
private static <T extends Enum> EnumFromMyModel genericConvert(T input) {
return input.name().equals(/*????*/) ?
EnumFromMyModel.FIRST_VALUE :
EnumFromMyModel.SECOND_VALUE;
}
You can do this if the enum value names of your and the external model are equal by converting the external enum to String and then converting this string back to your enum like this:
private static EnumFromMyModel genericConvert(Enum<?> input) {
return EnumFromMyModel.valueOf(input.name());
}
This will throw an IllegalArgumentException in case no matching enum from EnumFromMyModel can be found.
Still, i'd rather not use this and create all those 20 methods you mentioned and explicitly convert each enum value in a compile time safe manner. IMHO, the benefit of having compile time safety outweighs the benefit of having to write a little less code.

Getting Enum from an integer having a Class<? extends Enum> object

I have seen this which is pretty nice solution if i had a string instead of integer, but in case all i have is the specific enum's class object and an integer, how to do i get the specific enum constant instance?
Relying on the ordinal value of Java enum constants is poor practice -- it's too easy to accidentally reorder them, which would then break your code. The better solution is to simply provide your own integer that you can use instead:
public enum MyThing {
FOO(1),
BAR(2),
BAZ(3);
private final int thingId;
private MyThing(int thingId) {
this.thingId = thingId;
}
public int getThingId() {
return thingId;
}
}
Then whenever you want to get the thingId from a MyThing, just call the getThingId() method:
void doSomething(MyThing thing) {
System.out.printf("Got MyThing object %s with ID %d\n",
thing.name(), thing.getThingId());
}
If you want to be able to look up a MyThing by its thingId, you can build a lookup table yourself and store it in a static final field:
private static final Map<Integer, MyThing> LOOKUP
= createLookupMap();
private static Map<Integer, MyThing> createLookupMap() {
Map<Integer, MyThing> lookupMap = new HashMap<>();
for (MyThing thing : MyThing.values()) {
lookupMap.put(thing.getThingId(), thing);
}
return Collections.unmodifiableMap(lookupMap);
}
public static MyThing getThingById(int thingId) {
MyThing result = LOOKUP.get(thingId);
if (result == null) {
throw new IllegalArgumentException(
"This is not a valid thingId: " + thingId);
}
return result;
}
If you end up having a lot of enum classes and you want to do a similar thing with each of them, you can define an interface for that:
public interface Identifiable {
int getId();
}
And then make your enum implement that interface:
public enum MyThing implements Identifiable {
...
#Override
public int getId() {
return thingId;
}
}
And then you could build a reusable mechanism for looking up an Identifiable object based on its ID.
seem to have found the answer :
((Class<? extends Enum>)clazz).getEnumConstants()[index]
although for any-one looking for that, you should consider following #Daniel Pryden answer as most likely that using this in most use cases i can think of is bad practice.

Can the compiler verify a generic type of an object through a generic method?

First of all, sorry for the bad title. I don't know how to describe the problem in a few words (maybe not even in many)...
I am refactoring some settings in our system to be more abstract. The current solution has multiple tables in the DB, one for each settings area. In order to add a new setting, you'll need to extend the schema, the hibernate class, all transfer object classes, getters/setters, etc. I felt that this is violating OCP (open-closed principle), thus the refactoring.
I've spent some time coming up with ideas on how to implement such an abstraction. My favourite idea so far is the following:
1 enum for each settings area
1 enum value for each setting
Each setting is a SettingsDefinition<T> class using a generic type
A SettingsService is using static get/set methods with generic types
So for example, a settings area could be:
public enum SettingsABC{
A(new SettingDefinition<Integer>("A", 123)),
B(new SettingDefinition<String>("B", "Hello")),
C(new SettingDefinition<Boolean>("C", false));
private SettingDefinition settingDefinition;
SettingsABC(SettingDefinition settingDefinition) {
this.settingDefinition = settingDefinition;
}
public SettingDefinition getDefinition() {
return settingDefinition;
}
}
Where the SettingDefinition is the following:
public class SettingDefinition<T> {
private String name;
private T defaultValue;
public SettingDefinition(String name, T defaultValue) {
this.name = name;
this.defaultValue = defaultValue;
}
public String getName() {
return name;
}
public T getDefaultValue() {
return defaultValue;
}
}
And the service to get/set the values would be:
public class SettingsService {
public static <T> T getSetting(SettingDefinition setting) {
// hit db to read
// return value
}
public static <T> void setSetting(SettingDefinition setting, T value) {
// hit db to write
}
}
And the consumer would look something like this:
String value = SettingsService.getSetting(SettingsABC.B.getDefinition());
SettingsService.setSetting(SettingsABC.A.getDefinition(), 123);
My problem is that I cannot enforce a compiler type check between the generic type of the SettingDefinition inside SettingsABC and the generic type of get/set methods of the service. So in essence, I can do this:
Integer value = SettingsService.getSetting(SettingsABC.B.getDefinition());
Where B's definition is of type String.
Also, I can do this:
SettingsService.setSetting(SettingsABC.A.getDefinition(), "A");
Where A's definition is an Integer.
Is there any way to use generics to force these two different generic types match?
You can convert the enum to the class:
public final class SettingsABC<T> {
public static final SettingsABC<Integer> A =
new SettingsABC<>(new SettingDefinition<>("A", 123));
public static final SettingsABC<String> B =
new SettingsABC<>(new SettingDefinition<>("B", "Hello"));
public static final SettingsABC<Boolean> C =
new SettingsABC<>(new SettingDefinition<>("C", false));
private final SettingDefinition<T> settingDefinition;
// private constructor, so nobody else would instantiate it
private SettingsABC(SettingDefinition<T> settingDefinition) {
this.settingDefinition = settingDefinition;
}
public SettingDefinition<T> getDefinition() {
return settingDefinition;
}
}
This way individual constants will be typed. Now you can use the type arguments for SettingService as well:
public static <T> T getSetting(SettingDefinition<T> setting) {
...
}
public static <T> void setSetting(SettingDefinition<T> setting, T value) {
...
}
Although it's not an enum anymore, it can be used mostly in the same way. If you need other methods which are usually available in enum, you can mimic them like this:
public String name() {
return settingDefinition.getName();
}
#Override
public String toString() {
return settingDefinition.getName();
}
// and so on

Can I add new methods to the String class in Java?

I'd like to add a method AddDefaultNamespace() to the String class in Java so that I can type "myString".AddDefaultNamespace() instead of DEFAULTNAMESPACE + "myString", to obtain something like "MyDefaultNameSpace.myString". I don't want to add another derived class either (PrefixedString for example).
Maybe the approach is not good for you but I personally hate using +. But, anyway, is it possible to add new methods to the String class in Java?
Thanks and regards.
String is a final class which means it cannot be extended to work on your own implementation.
Well, actually everyone is being unimaginative. I needed to write my own version of startsWith method because I needed one that was case insensitive.
class MyString{
public String str;
public MyString(String str){
this.str = str;
}
// Your methods.
}
Then it's quite simple, you make your String as such:
MyString StringOne = new MyString("Stringy stuff");
and when you need to call a method in the String library, simple do so like this:
StringOne.str.equals("");
or something similar, and there you have it...extending of the String class.
As everyone else has noted, you are not allowed to extend String (due to final). However, if you are feeling really wild, you can modify String itself, place it in a jar, and prepend the bootclasspath with -Xbootclasspath/p:myString.jar to actually replace the built-in String class.
For reasons I won't go into, I've actually done this before. You might be interested to know that even though you can replace the class, the intrinsic importance of String in every facet of Java means that it is use throughout the startup of the JVM and some changes will simply break the JVM. Adding new methods or constructors seems to be no problem. Adding new fields is very dicey - in particular adding Objects or arrays seems to break things although adding primitive fields seems to work.
It is not possible, since String is a final class in Java.
You could use a helper method all the time you want to prefix something. If you don't like that you could look into Groovy or Scala, JRuby or JPython both are languages for the JVM compatible with Java and which allow such extensions.
YES!
Based on your requirements (add a different namespace to a String and not use a derived class) you could use project Lombok to do just that and use functionality on a String like so:
String i = "This is my String";
i.numberOfCapitalCharacters(); // = 2
Using Gradle and IntelliJ idea follow the steps below:
Download the lombok plugin from intelliJ plugins repository.
add lombok to dependencies in gradle like so: compileOnly 'org.projectlombok:lombok:1.16.20'
go to "Settings > Build > Compiler > Annotation Processors" and enable annotation processing
create a class with your extension functions and add a static method like this:
public class Extension {
public static String appendSize(String i){
return i + " " + i.length();
}
}
annotate the class where you want to use your method like this:
import lombok.experimental.ExtensionMethod;
#ExtensionMethod({Extension.class})
public class Main {
public static void main(String[] args) {
String i = "This is a String!";
System.out.println(i.appendSize());
}
}
Now you can use the method .appendSize() on any string in any class as long as you have annotated it and the produced result for the above example
This is a String!
would be:
This is a String! 17
The class declaration says it all pretty much,as you cannot inherit it becouse it's final.
You can ofcourse implement your own string-class, but that is probaby just a hassle.
public final class String
C# (.net 3.5) have the functionality to use extender metods but sadly java does not. There is some java extension called nice http://nice.sourceforge.net/ though that seems to add the same functionality to java.
Here is how you would write your example in the Nice language (an extension of
Java):
private String someMethod(String s)
{
return s.substring(0,1);
}
void main(String[] args)
{
String s1 = "hello";
String s2 = s1.someMethod();
System.out.println(s2);
}
You can find more about Nice at http://nice.sf.net
Not possible, and that's a good thing. A String is a String. It's behaviour is defined, deviating from it would be evil. Also, it's marked final, meaning you couldn't subclass it even if you wanted to.
As everybody else has said, no you can't subclass String because it's final. But might something like the following help?
public final class NamespaceUtil {
// private constructor cos this class only has a static method.
private NamespaceUtil() {}
public static String getDefaultNamespacedString(
final String afterDotString) {
return DEFAULT_NAMESPACE + "." + afterDotString;
}
}
or maybe:
public final class NamespacedStringFactory {
private final String namespace;
public NamespacedStringFactory(final String namespace) {
this.namespace = namespace;
}
public String getNamespacedString(final String afterDotString) {
return namespace + "." + afterDotString;
}
}
People searching with keywords "add method to built in class" might end up here. If you're looking to add method to a non final class such as HashMap, you can do something like this.
public class ObjectMap extends HashMap<String, Object> {
public Map<String, Object> map;
public ObjectMap(Map<String, Object> map){
this.map = map;
}
public int getInt(String K) {
return Integer.valueOf(map.get(K).toString());
}
public String getString(String K) {
return String.valueOf(map.get(K));
}
public boolean getBoolean(String K) {
return Boolean.valueOf(map.get(K).toString());
}
#SuppressWarnings("unchecked")
public List<String> getListOfStrings(String K) {
return (List<String>) map.get(K);
}
#SuppressWarnings("unchecked")
public List<Integer> getListOfIntegers(String K) {
return (List<Integer>) map.get(K);
}
#SuppressWarnings("unchecked")
public List<Map<String, String>> getListOfMapString(String K) {
return (List<Map<String, String>>) map.get(K);
}
#SuppressWarnings("unchecked")
public List<Map<String, Object>> getListOfMapObject(String K) {
return (List<Map<String, Object>>) map.get(K);
}
#SuppressWarnings("unchecked")
public Map<String, Object> getMapOfObjects(String K) {
return (Map<String, Object>) map.get(K);
}
#SuppressWarnings("unchecked")
public Map<String, String> getMapOfStrings(String K) {
return (Map<String, String>) map.get(K);
}
}
Now define a new Instance of this class as:
ObjectMap objectMap = new ObjectMap(new HashMap<String, Object>();
Now you can access all the method of the built-in Map class, and also the newly implemented methods.
objectMap.getInt("KEY");
EDIT:
In the above code, for accessing the built-in methods of map class, you'd have to use
objectMap.map.get("KEY");
Here's an even better solution:
public class ObjectMap extends HashMap<String, Object> {
public ObjectMap() {
}
public ObjectMap(Map<String, Object> map){
this.putAll(map);
}
public int getInt(String K) {
return Integer.valueOf(this.get(K).toString());
}
public String getString(String K) {
return String.valueOf(this.get(K));
}
public boolean getBoolean(String K) {
return Boolean.valueOf(this.get(K).toString());
}
#SuppressWarnings("unchecked")
public List<String> getListOfStrings(String K) {
return (List<String>) this.get(K);
}
#SuppressWarnings("unchecked")
public List<Integer> getListOfIntegers(String K) {
return (List<Integer>) this.get(K);
}
#SuppressWarnings("unchecked")
public List<Map<String, String>> getListOfMapString(String K) {
return (List<Map<String, String>>) this.get(K);
}
#SuppressWarnings("unchecked")
public List<Map<String, Object>> getListOfMapObject(String K) {
return (List<Map<String, Object>>) this.get(K);
}
#SuppressWarnings("unchecked")
public Map<String, Object> getMapOfObjects(String K) {
return (Map<String, Object>) this.get(K);
}
#SuppressWarnings("unchecked")
public Map<String, String> getMapOfStrings(String K) {
return (Map<String, String>) this.get(K);
}
#SuppressWarnings("unchecked")
public boolean getBooleanForInt(String K) {
return Integer.valueOf(this.get(K).toString()) == 1 ? true : false;
}
}
Now you don't have to call
objectMap.map.get("KEY");
simply call
objectMap.get("KEY");
Better use StringBuilder, which has method append() and does the job you want. The String class is final and can not be extended.
No You Cannot Modify String Class in java. Because It's final class. and every method present in final class by default will be final.
The absolutely most important reason that String is immutable or final is that it is used by the class loading mechanism, and thus have profound and fundamental security aspects.
Had String been mutable or not final, a request to load "java.io.Writer" could have been changed to load "mil.vogoon.DiskErasingWriter"
All is said by the other contributors before. You can not extend String directly because it is final.
If you would use Scala, you can use implicit conversions like this:
object Snippet {
class MyString(s:String) {
def addDefaultNamespace = println("AddDefaultNamespace called")
}
implicit def wrapIt(s:String) = new MyString(s)
/** test driver */
def main(args:Array[String]):Unit = {
"any java.io.String".addDefaultNamespace // !!! THAT is IT! OR?
}
The Java String class is a final, making it immutable. This is for efficiency reasons and that it would be extremely difficult to logically extend without error; the implementers have therefore chosen to make it a final class meaning it cannot be extended with inheritance.
The functionality you wish your class to support is not properly part of the regular responsibilities of a String as per the single responsibility principle, a namespace it is a different abstraction, it is more specialised. You should therefore define a new class, which includes String a member and supports the methods you need to provide the namespace management you require.
Do not be afraid to add abstractions (classes) these are the essence of good OO design.
Try using a class responsibility collaboration (CRC) card to clarify the abstraction you need.
You can do this easily with Kotlin. You can run both the kotlin code from within the java and the java code from the kotlin.
Difficult jobs that you can do with Java can be done more easily with Kotlin. I recommend every java developer to learn kotlin.
Referance: https://kotlinlang.org/docs/java-to-kotlin-interop.html
Example:
Kotlin StringUtil.kt File
#file:JvmName("StringUtil")
package com.example
fun main() {
val x: String = "xxx"
println(x.customMethod())
}
fun String.customMethod(): String = this + " ZZZZ"
Java Code:
package com.example;
public class AppStringCustomMethod {
public static void main(String[] args) {
String kotlinResponse = StringUtil.customMethod("ffff");
System.out.println(kotlinResponse);
}
}
output:
ffff ZZZZ
You can create your own version of String class and add a method :-)
Actually , you can modify the String class . If you edit the String.java file located in src.zip , and then rebuild the rt.jar , the String class will have more methods added by you . The downside is that that code will only work on your computer , or if you provide your String.class , and place it in the classpath before the default one .

How can I eliminate duplicated Enum code?

I have a large number of Enums that implement this interface:
/**
* Interface for an enumeration, each element of which can be uniquely identified by its code
*/
public interface CodableEnum {
/**
* Get the element with a particular code
* #param code
* #return
*/
public CodableEnum getByCode(String code);
/**
* Get the code that identifies an element of the enum
* #return
*/
public String getCode();
}
A typical example is:
public enum IMType implements CodableEnum {
MSN_MESSENGER("msn_messenger"),
GOOGLE_TALK("google_talk"),
SKYPE("skype"),
YAHOO_MESSENGER("yahoo_messenger");
private final String code;
IMType (String code) {
this.code = code;
}
public String getCode() {
return code;
}
public IMType getByCode(String code) {
for (IMType e : IMType.values()) {
if (e.getCode().equalsIgnoreCase(code)) {
return e;
}
}
}
}
As you can imagine these methods are virtually identical in all implementations of CodableEnum. I would like to eliminate this duplication, but frankly don't know how. I tried using a class such as the following:
public abstract class DefaultCodableEnum implements CodableEnum {
private final String code;
DefaultCodableEnum(String code) {
this.code = code;
}
public String getCode() {
return this.code;
}
public abstract CodableEnum getByCode(String code);
}
But this turns out to be fairly useless because:
An enum cannot extend a class
Elements of an enum (SKYPE, GOOGLE_TALK, etc.) cannot extend a class
I cannot provide a default implementation of getByCode(), because DefaultCodableEnum is not itself an Enum. I tried changing DefaultCodableEnum to extend java.lang.Enum, but this doesn't appear to be allowed.
Any suggestions that do not rely on reflection?
Thanks,
Don
You could factor the duplicated code into a CodeableEnumHelper class:
public class CodeableEnumHelper {
public static CodeableEnum getByCode(String code, CodeableEnum[] values) {
for (CodeableEnum e : values) {
if (e.getCode().equalsIgnoreCase(code)) {
return e;
}
}
return null;
}
}
Each CodeableEnum class would still have to implement a getByCode method, but the actual implementation of the method has at least been centralized to a single place.
public enum IMType implements CodeableEnum {
...
public IMType getByCode(String code) {
return (IMType)CodeableEnumHelper.getByCode(code, this.values());
}
}
Abstract enums are potentially very useful (and currently not allowed). But a proposal and prototype exists if you'd like to lobby someone in Sun to add it:
http://freddy33.blogspot.com/2007/11/abstract-enum-ricky-carlson-way.html
Sun RFE:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6570766
To tidy up dave's code:
public class CodeableEnumHelper {
public static <E extends CodeableEnum> E getByCode(
String code, E[] values
) {
for (E e : values) {
if (e.getCode().equalsIgnoreCase(code)) {
return e;
}
}
return null;
}
}
public enum IMType implements CodableEnum {
...
public IMType getByCode(String code) {
return CodeableEnumHelper.getByCode(code, values());
}
}
Or more efficiently:
public class CodeableEnumHelper {
public static <E extends CodeableEnum> Map<String,E> mapByCode(
E[] values
) {
Map<String,E> map = new HashMap<String,E>();
for (E e : values) {
map.put(e.getCode().toLowerCase(Locale.ROOT), value) {
}
return map;
}
}
public enum IMType implements CodableEnum {
...
private static final Map<String,IMType> byCode =
CodeableEnumHelper.mapByCode(values());
public IMType getByCode(String code) {
return byCode.get(code.toLowerCase(Locale.ROOT));
}
}
I had a similar issue with a localization component that I wrote. My component is designed to access localized messages with enum constants that index into a resource bundle, not a hard problem.
I found that I was copying and pasting the same "template" enum code all over the place. My solution to avoid the duplication is a code generator that accepts an XML configuration file with the enum constant names and constructor args. The output is the Java source code with the "duplicated" behaviors.
Now, I maintain the configuration files and the generator, not all of the duplicated code. Everywhere I would have had enum source code, there is now an XML config file. My build scripts detect out-of-date generated files and invoke the code generator to create the enum code.
You can see this component here. The template that I was copying and pasting is factored out into an XSLT stylesheet. The code generator runs the stylesheet transformation. An input file is quite concise compared to the generated enum source code.
HTH,
Greg
Unfortunately, I don't think that there is a way to do this. Your best bet would pro ably be to give up in emums altogether and use conventional class extension and static members. Otherwise, get used to duplicating that code. Sorry.
Create a type-safe utility class which will load enums by code:
The interface comes down to:
public interface CodeableEnum {
String getCode();
}
The utility class is:
import java.lang.reflect.InvocationTargetException;
public class CodeableEnumUtils {
#SuppressWarnings("unchecked")
public static <T extends CodeableEnum> T getByCode(String code, Class<T> enumClass) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
T[] allValues = (T[]) enumClass.getMethod("values", new Class[0]).invoke(null, new Object[0]);
for (T value : allValues) {
if (value.getCode().equals(code)) {
return value;
}
}
return null;
}
}
A test case demonstrating usage:
import junit.framework.TestCase;
public class CodeableEnumUtilsTest extends TestCase {
public void testWorks() throws Exception {
assertEquals(A.ONE, CodeableEnumUtils.getByCode("one", A.class));
assertEquals(null, CodeableEnumUtils.getByCode("blah", A.class));
}
enum A implements CodeableEnum {
ONE("one"), TWO("two"), THREE("three");
private String code;
private A(String code) {
this.code = code;
}
public String getCode() {
return code;
}
}
}
Now you are only duplicating the getCode() method and the getByCode() method is in one place. It might be nice to wrap all the exceptions in a single RuntimeException too :)
Here I have another solution:
interface EnumTypeIF {
String getValue();
EnumTypeIF fromValue(final String theValue);
EnumTypeIF[] getValues();
class FromValue {
private FromValue() {
}
public static EnumTypeIF valueOf(final String theValue, EnumTypeIF theEnumClass) {
for (EnumTypeIF c : theEnumClass.getValues()) {
if (c.getValue().equals(theValue)) {
return c;
}
}
throw new IllegalArgumentException(theValue);
}
}
The trick is that the inner class can be used to hold "global methods".
Worked pretty fine for me. OK, you have to implement 3 Methods, but those methods,
are just delegators.
It seems like you are actually implementing run time type information. Java provides this as a language feature.
I suggest you look up RTTI or reflection.
I don't think this is possible. However, you could use the enum's valueOf(String name) method if you were going to use the enum value's name as your code.
How about a static generic method? You could reuse it from within your enum's getByCode() methods or simply use it directly. I always user integer ids for my enums, so my getById() method only has do do this: return values()[id]. It's a lot faster and simpler.
If you really want inheritance, don't forget that you can implement the enum pattern yourself, like in the bad old Java 1.4 days.
About as close as I got to what you want was to create a template in IntelliJ that would 'implement' the generic code (using enum's valueOf(String name)). Not perfect but works quite well.
In your specific case, the getCode() / getByCode(String code) methods seems very closed (euphemistically speaking) to the behaviour of the toString() / valueOf(String value) methods provided by all enumeration. Why don't you want to use them?
Another solution would be not to put anything into the enum itself, and just provide a bi-directional map Enum <-> Code for each enum. You could e.g. use ImmutableBiMap from Google Collections for this.
That way there no duplicate code at all.
Example:
public enum MYENUM{
VAL1,VAL2,VAL3;
}
/** Map MYENUM to its ID */
public static final ImmutableBiMap<MYENUM, Integer> MYENUM_TO_ID =
new ImmutableBiMap.Builder<MYENUM, Integer>().
put(MYENUM.VAL1, 1).
put(MYENUM.VAL2, 2).
put(MYENUM.VAL3, 3).
build();
In my opinion, this would be the easiest way, without reflection and without adding any extra wrapper to your enum.
You create an interface that your enum implements:
public interface EnumWithId {
public int getId();
}
Then in a helper class you just create a method like this one:
public <T extends EnumWithId> T getById(Class<T> enumClass, int id) {
T[] values = enumClass.getEnumConstants();
if (values != null) {
for (T enumConst : values) {
if (enumConst.getId() == id) {
return enumConst;
}
}
}
return null;
}
This method could be then used like this:
MyUtil.getInstance().getById(MyEnum.class, myEnumId);

Categories

Resources