Chaining Enumerations for hierarchical naming structures? - java

Since I have a terrible memory, I like to put all the detnd I ails of data objects into enumerations, so I can use code completion in the IDE adon't have to keep referring back to get the name of a table or the name of a field. Usually I use some type of class containing only Enums for the purpose.
Lets say I have table of "Domains" (database source) "Tables" and "Fields" that look something like this:
public class DataObjectNames {
public enum Domains {
Domain1,
Domain2;
}
public enum Domain1Tables {
Customers,
Orders;
}
public enum Domain2Tables {
OrderItems,
Shipments;
}
public enum CustomerFields {
id,
email;
}
public enum OrderFields {
id,
customerId;
}
//fields for OrderItems and Shipments . . .
}
But suppose I wanted to be able to do something like:
Domain1.tables().Customers.fields(). //code completion supplies choices?
What I would like ot happen after I type the period is for autocomplete to provide a choice between .id and .email, much the same as it would if "fields" returned an object with two methods, or if I just typed
CustomerFields.
in the IDE.
In order for that to happen, it seems to me I somehow need to return not a specific instance of an enumeration, but the enumeration itself. I've tried various approaches like this:
public enum Domains {
Domain1 {
#Override
public Enum<?> tables() {
return Domain1Tables.foo();
} //Is there a method that will return the enum itself?
},
Domain2 {
#Override
public Enum<?> tables() {
return Domain2Tables.foo();
};
public abstract Enum<?> tables();
}
But of course I haven't been able to find a funciton foo() that returns the enum class itself.
Any thoughts?

You can't do this with enums because Java's class model doesn't work the way you would need in order for this style to work.
I haven't been able to find a function foo() that returns the enum class itself.
Returning the enum class itself is easy, you just do Domain1Tables.class, but that won't give you the completion you want because what it gives you is a Class<Domain1Tables> object, and that object doesn't have fields named Customers and Orders.
You want to be able to treat the "Domain1Tables" class as if it's an object and refer to the enum constants (which are effectively static final fields) as if they were members of that object, but Java simply doesn't do that.
If you give up on using enums for it, then you can simply have:
public class DataObjectNames {
public class Domains {
class Domain1 {
class Tables {
class Customers {
public static final String id = "id";
public static final String email = "email";
}
}
}
}
}
but in that case DataObjectNames.Domains.Domain1 wouldn't be a valid expression anymore (because it reference to a class scope, but not to an object.
There's probably a solution to what you're trying to do, but without more context I can provide anything more details than what's above.

Related

Is it possible to have an enum where each item is associated with a class?

I'm creating a game with hundreds of abilities, so trying to leverage abstracts and generics as much as possible.
Each ability extends an abstract Ability class with universal methods like getCooldown(player), which gets a specific ability's cooldown for a player. Inheritance saves me from having to duplicate that code in every ability class.
public abstract class Ability {
public static String getCooldown() {
int cooldown;
//logic to get cooldown in milliseconds
return cooldown;
}
}
But the logic and metadata for each ability are unique and coded like such:
public class Parry extends Ability {
public static String getDescription() {
...
}
public static void castAbility() {
...
}
}
Here's my enum. I'm using an enum because abilities and their metadata are constants that are ideally available at compile time. I also don't want to store the metadata separate from the classes which have the rest of the ability logic.
public enum AbilityEnum {
BORN_READY(BornReady.class),
JUGGLER(Juggler.class),
...
PARRY(Parry.class);
public final Class<? extends Ability> cls;
AbilityEnum(Class<? extends Ability> cls) {
this.cls = cls;
}
}
In other parts of the codebase, I want to use the Enum to generically get basic info on an ability, cast a spell, etc. I want to avoid hard-coding for any specific ability because there are 200+ of them. For example, when a player opens their skill menu, I need to grab the descriptions for every ability. I'd rather not type [ability_name].getDescription() 200+ times.
for (AbilityEnum ability : AbilityEnum.values()) {
String tooltip = ability.cls.getDescription();
...
// load descriptions into menu system so players
// can hover abilities for a tooltip description
}
If I try to run this I get the error:
Cannot resolve method 'getDescription' in 'Class'
This confuses me because I bounded the generic, so why does it think it has a Class instead of an Ability? I think I'm either misusing generics or have the wrong syntax for calling methods this way. Perhaps I should be using a list or something else instead of an enum?

Best way to store and access a lot of constants

When making a game for example I have a lot of constants I would like to store. I would also like a lot of classes to be able to access these constants. What would be the best way to store and access all these values. Currently, I just store final values in a separate class and then create an instance of the class storing the constants. And to access the values I would do "objectName.nameOfConstant". So my question is, is their a formal way to store all these constants or a better way.
One possible solution is to have a class with static properties, so you don't need to create the instance. e.g.:
public class Status {
public static final String ACTIVE = "ACTIVE";
public static final String INACTIVE = "INACTIVE";}
It can be called directly: Status.ACTIVE or Status.INACTIVE
Second possible solution is using Enum.
public enum Status {
ACTIVE, INACTIVE;
}
Using static String is easy, but there is no type check. For example when you want to put the constant as method input parameter:
public void process(String input, String status)
When using enum
public void process(String input, Status status)
Enum will make sure your input is from the enum list. While static String can't check it, so the user of the method can put any value in the "status", and you need to make sure the method will not break if the value is something unexpected.
You may consider using an Interface to store constance values in it.
At first it may seems strange, but the interface provide many useful default settings to store const variables, such as
final value by default
static and public access by default
does not need class instance
see below code example
public interface OlympicMedal
{
String GOLD = "Gold";
String SILVER = "Silver";
String BRONZE = "Bronze";
}
//some other file
import static xx.OlympicMedal;
public class OlympicAthlete
{
...
public static boolean isWinner(String medal) {
return OlympicMedal.GOLD.equals(medal);
}
}
** Important note : you should NOT use Const interface in an inheritance way (see code below), which is known as the interface pattern and is consider a poor practice
public class OlympicAthlete implements OlympicMedal // NOT recommended
{
...
}

How to expose an enum to public API without the implementation?

I have a class which has a property whose type is an Enum. Example:
enum CarType {
TOYOTA("Japan"),
AUDI("Germany"),
BMW("Germany");
public final String country;
private CarType(String country) { this.country = country; }
}
class Car {
private CarType type;
public CarType getType() { return type; }
}
The class Car is part of a library, and I would like to expose its functionality, so I create an interface which will be part of the public API, and have the class Car implement it:
interface ICar {
CarType getType();
}
class Car implements ICar {
private CarType type;
#Override public CarType getType() { return type; }
}
The problem with this approach is that this would require the whole CarType enum to be published. The CarType enum might contain additional attributes and methods which I do not want to expose / publish (country in this example).
What can I do if I want to hide the implementation of CarType but I still want to expose the possible values (the declared enum values) in a way so that the API users can reference them in switch and if statements like this:
ICar car = ...; // Get an instance somehow.
if (car.getType() == CarType.TOYOTA) System.out.println("It's Toyota.");
Making the additional attributes and methods protected or private is not a good solution because then other parts of the library would also not be able to reference to them.
Are there any good alternatives to this problem if I want to keep using Enums?
Although a late one wanted to add my thoughts -
enums can also implement an interface where you can expose only the require details:
public enum CarType implements ICarType {
...
public String getTypeName(){
return name();
}
}
public interface ICarType {
public String getTypeName();
}
So that you plan to use it in if()/switch
ICarType carType; //Not referencing the enum
if("TOYOTA".equalsIgnoreCase(carType.getTypeName())){
print("Toyota....");
}
You can provide Enum for public API, and convert it to another Enum for private usage.
E.g. use a Map, where key is public Enum instance and value - private Enum instance.
The problem is that you have to convert data each time the API is called. May require change in many places.
protected, private and package-private are the main tools you are provided with for this. If you think about your class hierarchy enough you can probably do something using them.
You should consider composition. Have a TypeDetails class, and have each member of the CarType contain a TypeDetails member. You can then restrict access to the TypeDetails getter to only those people who are supposed to access it while having the TypeDetails itself visible to all the parts of your library.
If it is strictly necessary to hide the country attribute to user code, you can go for standard visibility (attributes declared without public, protected or private qualifier, those attributes would only be visible for classes in the same package). I hope this to be useful, but I am aware that is only a patch.
Anyway I cannot fully understand your design and necessities, so probably you have no other option, but maybe what you need is a redesign with encapsulation in mind if you want to protect your code from API misuse

Associating a generic type with Enum in Java

I am creating a store for user preferences, and there are a fixed number of preferences that users can set values for. The names of the preferences (settings) are stored as an Enum:
public enum UserSettingName {
FOO,
BAR,
ETC
}
What I would like to be able to do is store a value type with the name so that the service will store the user's value with the correct Java type. For example, FOO might be a Long, and BAR might be a String. Up until now, we were storing all values as Strings, and then manually casting the values into the appropriate Java type. This has lead to try/catch blocks everywhere, when it makes more sense to have only one try/catch in the service. I understand that Enums cannot have generic types, so I have been playing around with:
public enum UserSettingName {
FOO(Long.class),
BAR(String.class),
ETC(Baz.class)
private Class type;
private UserSettingName(Class type) {
this.type = type;
}
public Class getType() {
return this.type;
}
}
I have a generic UserSetting object that has public T getSettingValue() and public void setSettingValue(T value) methods that should return and set the value with the correct type. My problem comes from trying to specify that generic type T when I create or retrieve a setting because I can't do something like:
new UserSetting<UserSettingName.FOO.getType()>(UserSettingName.FOO, 123L)
Sorry if this isn't exactly clear, I can try to clarify if it's not understood.
Thanks!
UPDATE
Both the setting name and value are coming in from a Spring MVC REST call:
public ResponseEntity<String> save(#PathVariable Long userId, #PathVariable UserSettingName settingName, #RequestBody String settingValue)
So I used the Enum because Spring casts the incoming data automatically.
Firstly you have to step back and think about what you're trying to achieve, and use a standard pattern or language construct to achieve it.
It's not entirely clear what you're going after here but from your approach it almost certainly looks like you're reinventing something which could be done in a much more straightforward manner in Java. For example, if you really need to know and work with the runtime classes of objects, consider using the reflection API.
On a more practical level - what you're trying to do here isn't possible with generics. Generics are a compile-time language feature - they are useful for avoiding casting everything explicitly from Object and give you type-checking at compilation time. You simply cannot use generics in this way, i.e. setting T as some value UserSettingName.Foo.getType() which is only known at runtime.
Look how it done by netty:
http://netty.io/wiki/new-and-noteworthy.html#type-safe-channeloption
They done it by using typed constants:
http://grepcode.com/file/repo1.maven.org/maven2/io.netty/netty-all/4.0.0.Beta1/io/netty/channel/ChannelOption.java#ChannelOption
EDIT:
public interface ChannelConfig {
...
<T> boolean setOption(ChannelOption<T> option, T value);
...
}
public class ChannelOption<T> ...
public static final ChannelOption<Integer> SO_TIMEOUT =
new ChannelOption<Integer>("SO_TIMEOUT");
...
}
EDIT2: you can transform it like:
class Baz {}
class UserSettingName<T> {
public static final UserSettingName<Baz> ETC = new UserSettingName<Baz>();
}
class UserSetting {
public <T> UserSetting(UserSettingName<T> name, T param) {
}
}
public class Test {
public static void main(String[] args) {
new UserSetting(UserSettingName.ETC, new Baz());
}
}
Enums are not the answer here. If you find yourself repeating code everywhere you could just create a utility class and encapsulate all the try/catch logic there. That would cut down on your code redundancy without majorly impacting your current code.
public class Util
{
public static MyObject getObjectFromString(String s)
{
try
{
return (MyObject)s;
}
catch(Exception e)
{
return null;
}
}
}
Then use as follows:
MyObject myObj = Util.getObjectFromString(string);

Inherited enum redefinition

It is more complex than it sounds, but I think I am obliged to try something like it. I want to make an abstract parent class with a prototyping of an enum (I want to declare the enum with only one value probably that will be the default unitialized one and also declaring a couple of methods that I will be using from the subclass), then I want to class that will extend the abstract parent to actually intialize the very same enum (I know that this practically hides the parent enum) so that the kid class will define a set of items inside the enum, but keep the methods probably.
I do not know much about this level of abstraction so I will now describe the nature of my problem, in case there is a more practical solution:
I have a bunch of files that contain classes that implement a lot of commands based on enums. (e.g. class1 implements Observer has an update method that uses an enum-based switch to decide what command was picked, same applies for the other classes) I now want to abstract this whole thing in a way that I have an enum variable with the exact same name in all classes (e.g. CommandSet) so that I can have a generic method inside the parent that will be able to print a help list to my system using the inside methods of the enum. Now I know I can rewrite the exact same method in every class, but I want to abstract it so that others can keep on extending the library I am making!
Hopefully I am not too confusing or too confused and somone can help me! :)
Edit: Here is an idea of the code (Probably not right):
public abstract class Commands{
enum CommandSet{
// empty command, placeholder
null_command ("command name", "command description");
// the Strings used for name and description
private final String name;
private final String description;
// constructor
CommandSet(String name, String description){
this.name=name;
this.description=description;
}
// get parameters
public String getName(){
return name;
}
public String getDescription(){
return description;
}
}
public void showHelp(){
for (CommandSet i : CommandSet.values()) {
printf(i.getName(),":",i.getDescription());
}
}
}
public class StandardCommads extends Commands implements Observer{
// I want to change the enum here, just changing the values so that null_command ("command name", "command description") will get removed and I will add a dozen other values, but keep the methods that the parent had
// update inherited from Observer
#Override
public void update(Observable observable, Object object) {
// I want the commands inside the switch cases defined inside this class's enum
switch(CommandSet.valueOf(String.valueOf(object)){
case command1: doStuff1();break;
case command2: doStuff2();break;
...
case commandN: doStuffN();break;
}
// other methods
void doStuff1(){
...
}
...
void doStuffN(){
...
}
}
public class NonStandardCommads extends Commands implements Observer{
// Another set of commands here for the enum keeping the same methods it had in the parent
// update inherited from Observer
#Override
public void update(Observable observable, Object object) {
// Other set of commands inside this class used in the switch statement
switch(CommandSet.valueOf(String.valueOf(object)){
case Zcommand1: doStuffz1();break;
case Zcommand2: doStuffz2();break;
...
case ZcommandN: doStuffzN();break;
}
// other methods
void doStuffz1(){
...
}
...
void doStuffzN(){
...
}
}
Impossible: Java enums can neither extend another class nor be extended themselves.
They can however implement interfaces. Perhaps you can use that to your advantage.
There is something else about enums that may help you: enums are not immutable. You could change field values of the enums, however that would change them for the whole JVM.
Another approach maybe to pass your subclass instances into a method of the enum and have the enum use your subclass as a call back to get different functionality out of an enum for a different user of the enum.
Nope, you can't do that.
Java Enums run out of gas very quickly & definitely, when you want to add/extend more definitions or instantiate the enum instances, at a later time. (eg load them from database, configure them in an instance method, not just statically.)
Behaviour/ or logic in Java enums is kinda limited too -- you can define & set properties, but only what's statically initializable, and logic seems basic (you end up mainly just comparing references or ordinals, with the other defined enum constants).
What you can do:
You can implement an ancestor Command or AbstractCommand class, with a integer Code, and then subclass it to define concrete values/ additional codes/ load or configure instances, etc.
For further benefit, you get efficient switch & despatch (by Code) plus the ability to define further details/properties, instantiate commands as-needed, etc.
Essentially, this is how you used to define an Enum before Java supported them. Though you may be using them as value objects, rather than strictly static.
My expertise:
I've done extensive compiler & type-system work, tried enums for file-types and associated data/behaviour.. explored the outer limits, and reached the definite boundaries.
I also like being able to instantiate & return a new UnknownFileType("") as an answer, too. Enums can't do that.
Example:
(We'll despatch by String, not int -- since your code appears to be using Java 7. This makes command resolution easier, than requiring both a syntactical "name" and an internal integer "code".)
public static class Command {
protected String code;
protected String desc;
public String getCode() {return code;}
public String getDesc() {return desc;}
public Command (String code, String desc) {
this.code = code;
this.desc = desc;
}
public String toString() {return code;}
}
public class StandardCommands {
public static Command READ = new Command("READ", "read a record");
public static Command CREATE = new Command("WRITE", "create a record");
public static Command EDIT = new Command("WRITE", "modify a record");
}
public class FurtherCommands extends StandardCommands {
public static Command LIST = new Command("LIST", "list all records");
}
public class QueryCommands extends FurtherCommands {
public static class QueryCmd extends Command {
protected String search;
public String getSearch() {return search;}
// constructor..
}
public static QueryCmd QUERY_EXAMPLE = new QueryCmd("QUERY", "example", "query for specified string");
public static QueryCmd createQuery (String search) {
return new QueryCmd( "QUERY", search, "query for specified string");
}
}

Categories