I have a class that overrides ArrayList like:
public class SkmeList extends ArrayList<SkmeStatement> {
private static final long serialVersionUID = 1L;
private int skmeMajor = 0;
private int skmeMinor = 0;
private String skmeTable = null;
public void setTable(String table) {
System.out.println("Set Table: " + table);
skmeTable = table;
}
public String getTable() {
return skmeTable;
}
public void setMajor(int major) {
System.out.println("SetMajor: " + major);
skmeMajor = major;
}
public int getMajor() {
return skmeMajor;
}
public void setMinor(int minor) {
System.out.println("SetMinor: " + minor);
skmeMinor = minor;
}
public int getMinor() {
return skmeMinor;
}
}
when I attempt to write this class to a file or even a string using jackson I can only see the list contents, I do not see any of class specific attributes like Major or minor in the string/file? I treat this class just like any other java class. Is there something that is different with lists in jackson object mapper?
public void WriteJson(SkmeList statements) {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final ObjectMapper mapper = new ObjectMapper();
try {
mapper.writeValue(out, statements);
final byte[] data = out.toByteArray();
System.out.println(new String(data));
}
catch (IOException ioe) {
System.out.println("Foo");
}
}
A List has elements and no further non-element data. If you need more data, you need something that's more than a List.
The user of your class already has to treat it specially if they care about any of the extra fields you've added.
In favoring composition over inheritance, here's how I'd suggest this class could look like.
public class SkmeList {
private final int major;
private final int minor;
private final String table;
private final List<SkmeStatement> statements;
// ctor, getters, hashCode, equals and toString omitted
}
With more context on what Skme means, we could make the naming even clearer.
To make it easier to reason about, the class should be immutable, to make it safe for use in a Collection it should have hashCode() and equals(), and a toString() in case it ever gets printed/logged/debugged around.
If you don't feel like implementing all the omitted methods, consider AutoValue: you specify the getters and a factory method, the rest is generated for you.
For the user of your class, it's almost the same:
SkmeList list = ...
for (SkmeStatement stmt : list) {
...
now becomes
SkmeList list = ...
for (SkmeStatement stmt : list.getStatements()) {
...
Related
I have created a simple class:
public class Example
{
private String name;
private int age;
// With getters and setters.
}
that I would like "put" into a chronicle map:
ChronicleMap<String,Example> map = ChronicleMapBuilder
.of(String.class, Example.class)
.name("example-map")
.entries(5_000)
.averageValue(new Example())
.valueMarshaller(ExampleSerializer.getInstance())
.averageKey("Horatio")
.createPersistedTo(new File("../logs/example.txt"));
However, I do not fully understand how to implement the ExampleSerializer class because I am not sure how the string member variables should be handled. How do I size strings? In the read and write methods, how do I read the string member variable, and how do I write the string member variable respectively. Pls note that on average, the name member string length will be between 7-10 characters. I have created the serializer below:
public class ExampleSerializer implements SizedReader<Example>,SizedWriter<Example>
{
private static ExampleSerializer INSTANCE = new ExampleSerializer();
public static ExampleSerializer getInstance() { return INSTANCE; }
private ExampleSerializer() {}
#NotNull
#Override
public Example read(Bytes in, long size, #Nullable Example using)
{
if (using == null)
using = new Example();
using.setAge(in.readInt());
using.setName(in.readUtf8()); // NOT SURE IF THIS IS CORRECT FOR A STRING
return using;
}
#Override
public long size(#NotNull Example toWrite)
{
return Integer.BYTES + ???; // NOT SURE WHAT THE SIZE SHOULD BE FOR STRING MEMBER?
}
#Override
public void write(Bytes out, long size, #NotNull Example toWrite)
{
out.writeInt(toWrite.getAge());
out.writeUtf8(toWrite.getName()); // NOT SURE IF THIS IS CORRECT FOR A STRING
}
}
I have this scenario. I started working with a system that 'process' documents. The problem is, it seems to be the typical scenario where it started small, and went getting bigger and bigger constructing it one chunk at a time and now it needs to be refactored.
Each document type has an identifier (docID), and all of them share the same underlying result structure.
There is a huge master class that does all the job BUT inside this class there are several methods (almost one for each site) with its own logic. They all do almost the same with slight changes (i.e. formatting a string before setting it to a field in the result structure or doing some calculation and then setting the field in the result structure).
For example:
private Result processDocGeneric(Result result){
result.setField1("value1");
result.setField2("value2");
result.setField3("value3");
return result;
}
private Result processDoc1(Result result){
result.setField1("VALUE1");
return result;
}
private Result processDoc2(Result result){
result.setField2("V-A-L-U-E-2");
return result;
}
private void processDocs(){
Result result = new Result();
result = processDocGeneric(result);
if(docID == 1){
result = processDoc1(result);
}
else if(docID == 2){
result = processDoc2(result);
}
...
}
Ok, so I'm planning to refactor this and I'm considering some design patterns I know but I don't want the feel that I'm killing a roach with a bazooka.
Command pattern is maybe the first that comes to my mind, also Strategy pattern. My major concern with those is that I will have to create a class for every document type that has its own implementation of the processDoc method (There are around 15 at the moment). I mean, if that's the way to go, that would be it but if there's a simpler way of doing it that I don't know, it would be better (since the change is in a single method).
The other thing that I could do is moving all those method to a 'methods' class, and also move the if-else block to a single method with a docID parameter (process(int docID) and then call it from the main class. But that's just splitting the huge class. It would be "cleaner" but not optimal.
What would be the best approach to clean and split this huge class and make it scalable (since there would be new document types to be added in the future)?.
You can use factory or abstract factory design patterns maybe, In this patterns you can get your needed objects without having to specify the exact class of the object that will be created.
I propose a solution based on the Visitable / Visitor Pattern. this solution requires very little change to the Result class, while opening the door to new visiting objects, making it an easily extensible framework. I'm making heavy use of Java8's default interface method.
The Visitor / Visitable Interfaces:
public interface DocVisitor<T extends VisitableDoc> {
default void visit(T document){
switch(document.getDocId()){
case 1:
processDoc1(document);
break;
case 2:
processDoc2(document);
break;
// ... other cases...
default:
processDocGeneric(document);
break;
}
}
void processDocGeneric(VisitableDoc document);
void processDoc1(VisitableDoc document);
void processDoc2(VisitableDoc document);
}
public interface VisitableDoc {
int getDocId();
default void visit(DocVisitor visitor){
visitor.visit(this);
}
}
Slight modification of the Result class:
public class Result implements VisitableDoc { // New interface declared
int getDocId(){
return docId; // This might already exist
}
// Rest is unchanged, the default implementation will suffice
}
A Visitor Implementation:
public class DocProcessor implements DocVisitor<Result> {
#Override
private Result processDocGeneric(Result result){
result.setField1("value1");
result.setField2("value2");
result.setField3("value3");
return result;
}
#Override
private Result processDoc1(Result result){
result.setField1("VALUE1");
return result;
}
#Override
private Result processDoc2(Result result){
result.setField2("V-A-L-U-E-2");
return result;
}
}
Usage:
public static final main(String[] args){
List<Result> results = // Obtain results somehow
DocProcessor processor = new DocProcessor();
for(Result result: results){
processor.visit(result);
}
}
[How to] split this huge class and make it scalable (since there would be new document types to be added in the future
What I've done is merely to split Document data on Result class / Document Processing on DocProcessor class. If you have other processing that differ from type to type, and which can be extracted to an external class (no need for private field handling, private methods calling etc.), this framework os completely applicable.
If not, you should REALLY consider refactoring it to use polymophism! Make each Document type its own object. Use a strong abstract class to link them all, and if you have many methods that are shared accross several but not all types, then make sub-types accordingly - or use default methods! Java8 FTW
For this situation is applicable builder pattern.
/**
*
* Hero, the class with many parameters.
*
*/
public final class Hero {
private final Profession profession;
private final String name;
private final HairType hairType;
private final HairColor hairColor;
private final Armor armor;
private final Weapon weapon;
private Hero(Builder builder) {
this.profession = builder.profession;
this.name = builder.name;
this.hairColor = builder.hairColor;
this.hairType = builder.hairType;
this.weapon = builder.weapon;
this.armor = builder.armor;
}
public Profession getProfession() {
return profession;
}
public String getName() {
return name;
}
public HairType getHairType() {
return hairType;
}
public HairColor getHairColor() {
return hairColor;
}
public Armor getArmor() {
return armor;
}
public Weapon getWeapon() {
return weapon;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("This is a ")
.append(profession)
.append(" named ")
.append(name);
if (hairColor != null || hairType != null) {
sb.append(" with ");
if (hairColor != null) {
sb.append(hairColor).append(' ');
}
if (hairType != null) {
sb.append(hairType).append(' ');
}
sb.append(hairType != HairType.BALD ? "hair" : "head");
}
if (armor != null) {
sb.append(" wearing ").append(armor);
}
if (weapon != null) {
sb.append(" and wielding a ").append(weapon);
}
sb.append('.');
return sb.toString();
}
/**
*
* The builder class.
*
*/
public static class Builder {
private final Profession profession;
private final String name;
private HairType hairType;
private HairColor hairColor;
private Armor armor;
private Weapon weapon;
/**
* Constructor
*/
public Builder(Profession profession, String name) {
if (profession == null || name == null) {
throw new IllegalArgumentException("profession and name can not be null");
}
this.profession = profession;
this.name = name;
}
public Builder withHairType(HairType hairType) {
this.hairType = hairType;
return this;
}
public Builder withHairColor(HairColor hairColor) {
this.hairColor = hairColor;
return this;
}
public Builder withArmor(Armor armor) {
this.armor = armor;
return this;
}
public Builder withWeapon(Weapon weapon) {
this.weapon = weapon;
return this;
}
public Hero build() {
return new Hero(this);
}
}
}
I have some class storing keys with important information. No one else is allowed to create a key, since a key relys on static information (like certain directory structures etc.).
public final class KeyConstants
{
private KeyConstants()
{
// could throw an exception to prevent instantiation
}
public static final Key<MyClass> MY_CLASS_DATA = new Key<MyClass>("someId", MyClass.class);
public static class Key<T>
{
public final String ID;
public final Class<T> CLAZZ;
private Key(String id, Class<T> clazz)
{
this.ID = id;
this.CLAZZ = clazz;
}
}
}
This example is simplyfied.
I wanted to test the consequences of a wrong key (exception handling, etc.) and instantiated the class via reflection in a JUnit test case.
Constructor<?> c = KeyConstants.Key.class.getDeclaredConstructor(String.class, Class.class);
c.setAccessible(true);
#SuppressWarnings ("unchecked")
KeyConstants.Key<MyClass> r = (KeyConstants.Key<MyClass>) c.newInstance("wrongId", MyClass.class);
Then I asked myself how could I prevent further instantiation of the key class (i. e. preventing further object creating via reflection)?
enums came to my mind, but they don't work with generics.
public enum Key<T>
{
//... Syntax error, enum declaration cannot have type parameters
}
So how can I keep a set of n instances of a generic class and prevent further instantiation?
So how can I keep a set of n instances of a generic class and prevent
further instantiation?
If you truly want to use this pattern, then no one (including you) should be able to instantiate a Key object. In order to keep a set of n instances in a class with this pattern, you could have a private constructor, a static method for access and a SecurityManager to prevent reflection. And since you want to be able to access the keys as pubic constants, I would try something like this..
public class KeyConstants{
// Here are your n instances for public access
public static final int KEY_1 = 1;
public static final int KEY_2 = 2;
.
.
.
public static final int KEY_N = 'n';
// now you can call this method like this..
// Key mKey = KeyConstants.getKey(KeyConstants.KEY_1);
public static Key getKey(int key){
List keys = Key.getInstances();
switch(key){
case KEY_1:
return keys.get(0);
case KEY_2:
return keys.get(1);
.
.
.
case KEY_N:
return keys.get(n);
default:
// not index out of bounds.. this means
// they didn't use a constant
throw new IllegalArgumentException();
}
}
static class Key<T>{
private static List<Key> instances;
private String ID;
private Class<T> CLAZZ;
private Key(String id, Class<T> clazz){
this.ID = id;
this.CLAZZ = clazz;
}
public static List<Key> getInstances(){
if(instances == null){
instances = new ArrayList<Key>();
//populate instances list
}
return instances;
}
}
}
Use SecurityManager to prevent reflection access.
//attempt to set your own security manager to prevent reflection
try {
System.setSecurityManager(new MySecurityManager());
} catch (SecurityException se) {
}
class MySecurityManager extends SecurityManager {
public void checkPermission(Permission perm) {
if (perm.getName().equals("suppressAccessChecks"))
throw new SecurityException("Invalid Access");
}
}
This will throw a SecurityException anytime someone attempts to access a private variable or field in your class (including access attempts via reflection).
I'm not sure I fully understand your question, but if a private constructor is not sufficient, can you use a more dynamic approach and throw an exception in the constructor after a signal is given? For example:
public static class Key<T>
{
private static boolean isLocked = false;
// Call this method when you want no more keys to be created
public static void lock() { isLocked = true; }
...
private Key(String id, Class<T> clazz)
{
if (isLocked) throw new IllegalStateException("Cannot create instances of Key");
this.ID = id;
this.CLAZZ = clazz;
}
}
Then - and this is the disadvantage - you will have to call Key.lock() once you want to prevent more instances being created.
As you showed in your code to prevent instantiating KeyConstants you can throw some Exception inside private-non-argument constructor.
Harder part is way to block creating KeyConstants.Key constructor from outside of KeyConstants class.
Some wild idea
Maybe create Exception in your constructor and check how its stack trace looks like. When I add this code to constructor
private Key(String id, Class<T> clazz) {
StackTraceElement[] stack = new Exception().getStackTrace();
for (int i=0; i<stack.length; i++){
System.out.println(i+") "+stack[i]);
}
this.ID = id;
this.CLAZZ = clazz;
}
and create instance of Key with reflection like
Constructor<?> c = KeyConstants.Key.class.getDeclaredConstructor(
String.class, Class.class);
c.setAccessible(true);
KeyConstants.Key<MyClass> r = (KeyConstants.Key<MyClass>) c
.newInstance("wrongId", MyClass.class);
I get
0) KeyConstants$Key.<init>(Test.java:38)
1) sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
2) sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
3) sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
4) java.lang.reflect.Constructor.newInstance(Constructor.java:525)
so maybe just if 4th element of stack is java.lang.reflect.Constructor.newInstance throw Exception to prevent executing rest of constructors code like:
if (stack.length>=4 && stack[4].toString().startsWith("java.lang.reflect.Constructor.newInstance")){
throw new RuntimeException("cant create object with reflection");
}
I came across some Multiton patterns recently, where I tried to handle problems with unique enum keys, that gave me the idea of another approach.
The keys can be used for information flow as I intended, or even as keys for typesafe heterogeneous container, where they can perform compile-time casting.
Key-defining class
public class KeyConstants
{
public static final KeysForIntegers SOME_INT_KEY = KeysForIntegers.KEY_2;
public static final KeysForStrings SOME_STRING_KEY = KeysForStrings.KEY_1;
public interface Key<Type>
{
public Class<Type> getType();
}
/* Define methods that classes working with the keys expect from them */
public interface KeyInformation
{
public String getInfo1();
// and so on...
}
public enum KeysForStrings implements Key<String>, KeyInformation
{
KEY_1("someId");
public final String ID;
private KeysForStrings(String id)
{
ID = id;
}
#Override
public String getInfo1()
{
return "Good piece of information on " + ID + ".";
}
#Override
public Class<String> getType()
{
return String.class;
}
}
public enum KeysForIntegers implements Key<Integer>, KeyInformation
{
KEY_2("bla");
public final String ID;
private KeysForIntegers(String id)
{
this.ID = id;
}
#Override
public String getInfo1()
{
return "Some info on " + ID + ".";
}
#Override
public Class<Integer> getType()
{
return Integer.class;
}
}
}
Example key-using class
public class KeyUser
{
public static void main(String[] args)
{
KeysForIntegers k1 = KeyConstants.SOME_INT_KEY;
KeysForStrings k2 = KeyConstants.SOME_STRING_KEY;
processStringKey(k2);
useIntKey(k1);
Integer i = useIntKey(KeyConstants.SOME_INT_KEY);
processStringKey(KeyConstants.SOME_STRING_KEY);
}
/* My methods should just work with my keys */
#SuppressWarnings ("unchecked")
public static <TYPE, KEY extends Enum<KeysForIntegers> & Key<TYPE> & KeyInformation> TYPE useIntKey(KEY k)
{
System.out.println(k.getInfo1());
return (TYPE) new Object();
}
public static <KEY extends Enum<KeysForStrings> & KeyInformation> void processStringKey(KEY k)
{
System.out.println(k.getInfo1());
// process stuff
}
}
I have another approach, you can bound an interface in a way to only be implemented by enum.
With that approach you have a fixed set of instances at compile time.
If you want to add lazy loading, the enums implementing it should be proxies that load the desired object if it is requested. The class or classes that are hidden behind the proxies should only be visible to them, so that they have exclusive access to the constructor.
public class User {
public static <S> S handleKey(FixedInstanceSet<S,?> key) {
return key.getKey();
}
}
interface FixedInstanceSet<S, T extends Enum<T> & FixedInstanceSet<S,T>>
{
public S getKey();
}
enum StringKeys implements FixedInstanceSet<String, StringKeys> {
TOP, DOWN, LEFT, RIGHT;
#Override
public String getKey() { return null; }
}
enum IntKeys implements FixedInstanceSet<Integer, IntKeys > {
TOP, DOWN, LEFT, RIGHT;
#Override
public Integer getKey() { return null; }
}
/*
* Bound mismatch: The type NotWorking is not a valid substitute for the bounded
* parameter <T extends Enum<T> & FixedInstanceSet<S,T>> of the type
* FixedInstanceSet<S,T>
*/
//class NotCompiling implements FixedInstanceSet<String, NotCompiling> {
//
// #Override
// public String getKey() { return null; }
//}
If I understand you correctly, you don't want your class to be instantiated.
You can set the default constructor to private
private Key() throws IllegalStateException //handle default constructor
{
throw new IllegalStateException();
}
This will prevent its improper instantiation.
Update:
added throw IllegalStateException
The idea I'm going for is that I have a bunch of actions/functions that happen in our program. They're all predefined and separated into categories. So there might be a category for admin actions that then defines a bunch of static codes for actions that are in the admin actions category.
Since the categories and actions are fixed, they're all in static classes.
These static category classes all implement an interface, ICategory:
public static interface ICategory{
int getCateogory();
String getCategoryName();
String getFunctionName(int function);
}
Each of these static classes is added to a static Map:
private static Map<Integer, Class<? extends ICategory>> catMap = new HashMap<Integer, Class<? extends ICategory>>();
Basically there's an integer code associated with each category. What I'm trying to do is just made a human readable string that I can print out when I receive the category and action codes. What I would like to do is something like
ICategory whatever = catMap.get(catNumber);
System.out.println(whatever.getCategoryName());
System.out.println(whatever.getFunctionName(actionCode));
So catMap.get(catNumber) will actually return the proper static class, but I then don't know how I can use that returned class to access these static methods. I can do it with regular instances of a class, just fine, but doing it with static classes has got me puzzled.
Clarification of Problem:
Some Clarification of The problem I'm trying to solve in case you guys have suggestions of better / more intuitive ways to do this:
Basically I'm interpreting commands from some piece of custom hardware at my company. It's a little data collection gizmo that has a bunch of predefined messages/functions that I have to interpret.
These functions are split into various categories: Display, Keypad, Acquisition, etc.
So basically I have a mapping like this:
Display Category: 128
ShowGraph: 01
ShowText: 02
Keypad Category: 129
F1: 01
F2: 02
MenuKey: 03
I'm making a little stream display that prints the stream of commands out in human readable format. So I'd just print out a big list of something like
Got Category Display, Function ShowGraph
Got Category Keypad, Function MenuKey
Normally I'd use a map for this, but what I want is to also use the functions in each category as constants because I'll have to reference them in if-statements and often times send those same categories back to the little gizmo.
For Instance:
sendMessage(Categories.DisplayCategory.getCategoryInt(), Categories.DisplayCategory.SHOW_GRAPH);
More Code as requested:
public class Functions {
public static interface ICategory{
int getCateogory();
String getCategoryName();
String getFunctionName(int function);
}
private static Map<Integer, Class<? extends ICategory>> catMap = new HashMap<Integer, Class<? extends ICategory>>();
public static String getCategoryString(int category) {
Class<? extends ICategory> clazz = catMap.get(category);
System.out.println(catMap.toString());
if(clazz != null){
try{
Method m = clazz.getMethod("getCategoryName", Integer.class);
return (String) m.invoke(0, category);
}catch (Exception e){
return null;
}
}else{
System.out.println("clazz was null");
return null;
}
}
public static class SystemKey implements ICategory{
public static int CATEGORY = 134;
private static Map<Integer, String> fmap = new HashMap<Integer, String>();
#Override
public int getCateogory() {
return CATEGORY;
}
#Override
public String getCategoryName() {
return "SystemKey";
}
#Override
public String getFunctionName(int function) {
return fmap.get(function);
}
}
public static class SystemCat implements ICategory{
public static int CATEGORY = 128;
private static Map<Integer, String> fmap = new HashMap<Integer, String>();
public static final int POWER_UP = 0x01;
public static final int END_OF_TRANSMIT = 0x02;
public static final int CLEAR_TO_SEND = 0x03;
public static final int NET_TEST = 0x05; /*Fom station to ctrlr*/
public static final int NET_OK = 0x06; /*Response to controller*/
public static final int MAIN_MENU = 0x07;
static{
catMap.put(CATEGORY, SystemCat.class);
fmap.put(POWER_UP, "POWER_UP");
fmap.put(END_OF_TRANSMIT, "END_OF_TRANSMIT");
fmap.put(CLEAR_TO_SEND, "CLEAR_TO_SEND");
fmap.put(NET_TEST, "NET_TEST");
fmap.put(NET_OK, "NET_OK");
fmap.put(MAIN_MENU, "MAIN_MENU");
}
#Override
public int getCateogory() {
return CATEGORY;
}
#Override
public String getCategoryName() {
return "System";
}
#Override
public String getFunctionName(int function) {
return fmap.get(function);
}
}
public static class SoftKey implements ICategory{
public static int CATEGORY = 129;
private static Map<Integer, String> fmap = new HashMap<Integer, String>();
public static final int F1 = 0x20;
public static final int F2 = 0x21;
public static final int F3 = 0x22;
public static final int F4 = 0x23;
public static final int F5 = 0x24;
static{
catMap.put(CATEGORY, SoftKey.class);
fmap.put(F1, "F1");
fmap.put(F2, "F2");
fmap.put(F3, "F3");
fmap.put(F4, "F4");
fmap.put(F5, "F5");
#Override
public int getCateogory() {
return CATEGORY;
}
#Override
public String getCategoryName() {
return "SoftKey";
}
#Override
public String getFunctionName(int function) {
return fmap.get(function);
}
}
public static void main (String[] args) throws Exception{
System.out.println(Functions.getCategoryString(128));
}
}
Update
As I suspected, the solution is quite simple. There are different ways to do this, here is one, I seem to remember calling it Registry, back in the days when Patterns were known as Idioms. You are almost there, what you need is following changes:
Change catMap type from Map<String,Class<? extends ICategory> to Map<Integer, ICategory>.
In the static initializers create an object and put it in the map, e.g.
public static class SoftKey implements ICategory{
....
static{
catMap.put(CATEGORY, new SoftKey());
In getCategoryString use the ICategory object in the registry:
ICategory categ = catMap.get(category);
return categ.getCategoyString()
I might have misunderstood the question, but part of it are confusing:
So catMap.get(catNumber) will actually return the proper static class,
By static class I assume you mean that the interfaces are nested inside some class/interface. There is no such thing as a top-level static class in Java. get returns an Object of a static class, not a class.
but I then don't know how I can use that returned class to access these static methods.
The methods you have declared are not static, they are instance methods
I can do it with regular instances of a class, just fine, but doing it with static classes has got me puzzled.
I am puzzled too. You can call instance methods on objects of static class. Can you post a complete code sample?
Assuming you know all the codes in advance, and there aren't 1000s of function values, this would work. The non-uniqueness of the function value codes isn't a problem as long as you don't mind looking through a container to find them (as opposed to a Map).
You could do away with the static maps completely if you don't mind looping through all the enum values all the time. This could be perfectly acceptable if you don't do lookups very often.
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public enum FunctionCategory {
DISPLAY(128, "Display"),
KEYPAD(129, "KeyPad");
// more categories here...
private final int code;
private final String name;
private static Map<Integer, FunctionCategory> categoryMap = new HashMap<>();
static {
for( FunctionCategory c : FunctionCategory.values() ) {
categoryMap.put(c.getCode(), c);
}
}
// For looking up a category from its code
public static FunctionCategory fromCode( int code ) {
return categoryMap.get(code);
}
private FunctionCategory(int code, String name) {
this.code = code;
this.name = name;
}
public int getCode() {
return code;
}
public String getName() {
return name;
}
public static enum FunctionValue {
// DISPLAY
DISPLAY_GRAPH(DISPLAY, 1, "Graph"),
DISPLAY_TEXT(DISPLAY, 2, "ShowText"),
//KEYPAD
KEYPAD_MENU(KEYPAD, 1, "MenuKey"),
KEYPAD_ENTER(KEYPAD, 2, "EnterKey");
// TODO, others
private static Map<FunctionCategory, Set<FunctionValue>> codeMapping = new EnumMap<>( FunctionCategory.class );
static {
for( FunctionValue fv : FunctionValue.values() ) {
Set<FunctionValue> values = codeMapping.get(fv.getCategory());
if( values == null ) {
values = EnumSet.of(fv);
}
else {
values.add(fv);
}
codeMapping.put(fv.getCategory(), values);
}
}
// First we look up the category, then we just loop over all the values
// within that category. Unless you have lots of values, or really need
// to optimize the lookups, there is no need to do something more complex
public static FunctionValue getFromCodes( int categoryCode, int valueCode ) {
FunctionCategory c = FunctionCategory.fromCode(categoryCode);
if( c != null ) {
Set<FunctionValue> valueSet = codeMapping.get(c);
if( valueSet != null ) {
// Just spin through them, there aren't that many
for( FunctionValue v : valueSet ) {
if( v.getCode() == valueCode ) {
return v;
}
}
}
}
return null;
}
private final FunctionCategory category;
private final int code;
private final String name;
private FunctionValue(FunctionCategory category, int code, String name) {
this.category = category;
this.code = code;
this.name = name;
}
public FunctionCategory getCategory() {
return category;
}
public int getCode() {
return code;
}
public String getName() {
return name;
}
}
}
I have encountered a weird problem in my app (java).
I have an enum. Something like that
public enum myEnum implement myIntrface{
valueA(1),valueb(2),valuec(3),valued(4)
private int i;
// and then - a constructor
public MyEnum(int number){
i = number;
}
private MyObj obj = new MyObj;
// getter and setter for obj
}
and in another class I have this
MyEnum.valueA.setObj(new Obj(...))
in briefe - I have an enum with a private instance member that has a set and a get.
So far so good -
The only thing that amazes me is that later on I look at the value of the MyEnum.valueA().obj is null.
there is nothing that updates the value to null, I have even gave it a default value in the constructor and I still see it null later.
any suggestions?
Enums should be un-modifiable classes so you shouldn't really be doing this. If your looking to modify the state of a type based object like an enum you should use an final class approach with embedded constants. Below is an example of a class based approach with a modifiable name an a un-modifiable name...
public final class Connection {
public static final Connection EMAIL = new Connection("email");
public static final Connection PHONE = new Connection("phone");
public static final Connection FAX = new Connection("fax");
/**/
private final String unmodifiableName; //<-- it's final
private String modifiableName;
/*
* The constructor is private so no new connections can be created outside.
*/
private Connection(String name) {
this.unmodifiableName = name;
}
public String getUnmodifiableName() {
return unmodifiableName;
}
public String getModifiableName() {
return modifiableName;
}
public void setModifiableName(String modifiableName) {
this.modifiableName = modifiableName;
}
}
The purpose of enums is to represent constant values. It does not make any sense to set the fields of a constant value.
You should declare your fields as final, and use the constructor to initialize all of them.
For reference, the following code works as expected:
public class Test {
public static enum MyEnum {
valueA(1),valueb(2),valuec(3),valued(4);
private int i;
private Object o;
private MyEnum(int number) {
i = number;
}
public void set(Object o) {
this.o = o;
}
public Object get() {
return o;
}
}
public static void main(String[] args) {
System.out.println(MyEnum.valueA.get()); // prints "null"
MyEnum.valueA.set(new Integer(42));
System.out.println(MyEnum.valueA.get()); // prints "42"
}
}
the cause of this problem is the db40 framework . It loads an enum from the db using reflection. This is well documented .
http://developer.db4o.com/Forums/tabid/98/aft/5439/Default.aspx