Exception class for objects of different classes - java

I'd like to write an exception class which is usable with different classes and specific behaviors. It works well with changing an object - like
a.setWeight(500)
- but it doesn't work in my constructor - like
Cheese b = new Cheese(500);
because the object is not being generated and null is inserted in my WeightException.
public class WeightException extends Exception {
private int attribute;
private Object object;
public WeightException(Object o, int a) throws WeightException {
object = o;
attribute = a;
}
public String getMessage() {
if(object instanceof Cheese)
return "Cheese is overweight.";
if(object instanceof Baggage)
return "Baggage is "+String.valueOf(attribute)+" kilos overweight.";
}
}
public class Cheese {
private int weight;
public Cheese(int weight) {
setWeight(weight);
}
public void setWeight(int weight) throws WeightException {
if(weight<200)
this.weight = weight;
else
throw new WeightException(this, weight);
}
}
Does anybody know a better approach to solve this than to insert a string with the class name in my exception class parameters?

Implement an interface in the classes you want to use with this exception.
The interface has a method to define a message, possible another to provide an attribute.
Alternatively, provide an array of attributes and use String.format to build the message.
Use that interface to define the object parameter passed in to the exception ctor.
Call that method in the exception to get the message.
Personally, I find this to be an anti-pattern, unless the classes you want to use with the exception are very tightly related. Otherwise you're giving up semantically-meaningful exception property names.
I'd rather see an app-specific superclass with subclasses with semantic meaning.

Here is a solution which would require that you use a "toy" project of mine (well, I already use it in other projects):
Make a base abstract class like this:
public abstract class WeightedItem
{
protected static final MessageBundle BUNDLE;
static {
// The day when you get serious, replace with a properties bundle
final MessageSource source = MapMessageSource.newBuilder()
.put(Cheese.class.getCanonicalName(), "cheese is overweight")
.put(Baggage.class.getCanonicalName(), "baggage is %d kilos overweight")
.build();
BUNDLE = MessageBundle.newBuilder().appendSource(source).freeze();
}
protected int weight;
protected final WeightException doException(final Object... params)
{
return new WeightException(BUNDLE.printf(getClass().getCanonicalName(),
params));
}
}
An implementation of Baggage would then do:
public class Baggage
extends WeightedItem
{
// ....
public void setWeight(int weight)
throws WeightException
{
if (overweight)
throw doException(weight);
}
}
As the implementation is both key-resistant (returns the key if missing) and format-resistant (returns the format string itself if format argument mismatch) you are guaranteed to have parameterized messages or quickly see where you got your messages wrong...

Have you actually tried running this code? The this variable is valid (non-null) within a constructor. Even if the constructor throws an exception, a new object has been created and can be referenced. See the JLS.

If you parameterize the exception with everything you need for the message, you can rid yourself of using instanceof, and make the exception usable by any class:
Also, it's not a good idea to hold a reference to the object that caused the exception - it's unnecessary, is a form of memory leak, but importantly if the exception is thrown from the constructor, will allow this to "escape" from the constructor (always bad).
public class WeightException extends Exception {
private final int attribute;
private final String className;
private final String units;
public WeightException(Object o, int a) {
this(o, a, null);
}
public WeightException(Object o, int a, String u) {
classname = o.getClass().getSimpleName(); // eg "Cheese"
attribute = a;
units = u == null ? "" : u + " ";
}
public String getMessage() {
return className " is " + attribute + " " + units + "overweight.";
}
}
You can now use this exception with any class without further modification of the exception or the client class, other than to provide the optional units:
From Cheese:
throw new WeightException(this, weight);
From Baggage:
throw new WeightException(this, weight, "kilos");

Related

Cannot cast to... android

I created some classes with inheritance concept, I have the main class for my application, that is called modulo, which corresponds to an module, and also some other classes called moduloLedRGB, ModuloSwitch, and ModuloDimmer, these 3 classes all extends the class modulo which has just the common arguments for modules like, id, name, Module type, and ipAdress. But, when I try to cast a module to one of those 3 childs classes I get an exception that says I cannot cast Modulo to ModuloSitch or ModuloLedRGB...
This is where I get the error:
switch (modulo.getModulo()){
case "RGB":
ModuloLedRGB rgb = (ModuloLedRGB) modulo;
rgb.setProgress(c.getDouble(c.getColumnIndex("progress")));
rgb.setProgressRed(c.getDouble(c.getColumnIndex("progressRed")));
rgb.setProgressGreen(c.getDouble(c.getColumnIndex("progressGreen")));
rgb.setProgressBlue(c.getDouble(c.getColumnIndex("progressBlue")));
break;
case "Dimmer":
ModuloDimmer dimmer = (ModuloDimmer) modulo;
dimmer.setProgress(c.getDouble(c.getColumnIndex("progress")));
break;
case"Switch":
ModuloSwitch sw = (ModuloSwitch) modulo;
break;
It says I cannot cast modulo that is an object corresponds to the class Modulo, to ModuloRGB.
getModulo returns a string that says me which kind of Module this is.
package br.com.andrey.projetointegradoapp;
/**
* Created by andrey on 04/08/2016.
*/
public class Modulo {
private long id;
private String nome;
private String ModuleIpAdress;
private String modulo;
public String getModulo() {
return modulo;
}
public void setModulo(String modulo) {
this.modulo = modulo;
}
public String getModuleIpAdress() {
return ModuleIpAdress;
}
public void setModuleIpAdress(String moduleIpAdress) {
ModuleIpAdress = moduleIpAdress;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
}
This is the Modulo Class.
and this is ModuloLedRGB class:
package br.com.andrey.projetointegradoapp;
/**
* Created by andrey on 16/12/2016.
*/
public class ModuloLedRGB extends Modulo {
private double progress;
private double progressRed;
private double progressGreen;
private double progressBlue;
public double getProgressRed() {
return progressRed;
}
public void setProgressRed(double progressRed) {
this.progressRed = progressRed;
}
public double getProgress() {
return progress;
}
public void setProgress(double progress) {
this.progress = progress;
}
public double getProgressGreen() {
return progressGreen;
}
public void setProgressGreen(double progressGreen) {
this.progressGreen = progressGreen;
}
public double getProgressBlue() {
return progressBlue;
}
public void setProgressBlue(double progressBlue) {
this.progressBlue = progressBlue;
}
}
Any ideas for why am I getting this exception? since the child extends the main class I think I should be able to cast it down, not?
Based on the comments, it appears that you misunderstand the nature of casting.
When you say
class Modulo { ... }
class ModuloLedRGB extends Modulo { ... }
Subclassing defines an is-a relationship; every ModuloLedRGB is also a Modulo. But that doesn't work both ways.
If you create an object with
new Modulo()
then it is a Modulo, but not a ModuloLedRGB. If you create it with
new ModuloLedRGB()
it is both a ModuloLedRGB and a Modulo. Saying it's a Modulo means that you can assign a variable of type Modulo to it, or use it as a Modulo parameter:
ModuloLedRGB x = new ModuloLedRGB();
Modulo y = x; // this is legal, but the object's class doesn't change
y is a reference to the ModuloLedRGB object. But note that although y is declared as Modulo, it still refers to the same object, whose class is ModuloLedRGB, because that's the way the object is created.
That's why you can use downcasting. Say you later use the expression
(ModuloLedRGB)y
At this point, the compiler knows only that y (if not null) is a Modulo; it could be an object of class Modulo, ModuloLedRGB, ModuloSwitch, or anything else. So at run time, the code checks to see what kind of object it's actually referring to. Since the example above set y to an object created as a ModuloLedRGB, the cast is successful. But if y were set to some other object that wasn't a ModuloLedRGB, the cast throws an exception.
This cast doesn't change an object, and it doesn't create a new object. It just says "Make sure the object is of class ModuloLedRGB, and then treat it as a ModuloLedRGB so that we can access methods and instance variables that are particular to a ModuloLedRGB".
It looks, however, that you're trying to convert the object by changing its class. You've created an object whose class is Modulo, and you're trying to come up with some new object whose class is ModuloLedRGB. You can't do that with a cast. If you have a Modulo and you want to create a ModuloLedRGB, you will have to create a new object with new ModuloLedRGB(), somewhere. One common way to do this is to write a constructor:
class ModuloLedRGB extends Modulo {
public ModuloLedRGB(Modulo m, maybe other parameters) {
// copy the instance variables from "m"
this.field = m.field;
this.anotherField = m.anotherField;
// set the new instance variables
this.newField = maybe a parameter or some other computation;
...
}
or write a static factory method to create a new ModuloLedRGB from a Modulo. But you'll have to create it, and you'll have to write the code to create it. You can't "convert" it from a Modulo. There's no such thing in Java.

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

Is there any way to access this.toString()'s value when calling another constructor?

For everyone who is talking about the fact that the object is in an "unitialized state", please refer to the answer to this question which shows that an object reference can be passed around, dereferenced, have methods invoked from it, and have fields accessed before a constructor terminates and all fields have been assigned (including final fields).
So here's the use case:
public class Entity {
private final String name;
public Entity() {
this(toString()); //Nope, Chuck Testa
}
public Entity(String name) {
this.name = name;
}
}
The compiler error is:
Cannot refer to an instance method while explicitly invoking a constructor.
Note that toString() has not been overriden and is the default call from Object.
I'm certainly interested in the philosophical/technical reasons behind this, so if anyone can explain that, that would be an awesome bonus. But I'm looking for a way to call toString() from that default constructor as it refers down to the more specific one with more arguments. The actual use case is a bit more complicated and ends up referring all the way down to a constructor with four arguments, but that shouldn't really matter.
I know I could do something like this...
private static final String TO_STRING_CONSTRUCTOR_ARGUMENT = "aflhsdlkfjlkswf";
public Entity() {
this(TO_STRING_CONSTRUCTOR_ARGUMENT);
}
public Entity(String name) {
this.name = name == TO_STRING_CONSTRUCTOR_ARGUMENT ? toString() : name;
}
... but it seems like a pretty inelegant solution.
So, any way to pull it off? Or any recommended best practices to deal with this situation?
I would prefer not to pass this around until the object is created. Instead I would do this:
public class Entity {
private final String name;
public Entity() {
this(null); // or whatever
}
public Entity(String name) {
this.name = name;
}
public String getName() {
return name != null ? name : Objects.hashCode(this);
}
}
If you can live without the final name, you can use an initializer block:
public class Entity {
private String name;
{name = this.toString();}
public Entity() {
}
public Entity(String name) {
this.name = name;
}
}
this is only available after all calls to this() or super() are done. The initializer runs first after the constructors call to super() and is allowed to access this.
As for the reasons why that is a compiler error, please see section 8.8.7 of the JLS. The reasons why this was made a compiler error are not clear, but consider that the constructor chain has to be the first thing executed when new'ing an Object and look at the order of evaluation here:
public Entity() {
this(toString());
}
toString() is evaluated first before the even the super constructor is invoked. In general this leaves open all kinds of possibilities for uninitialized state.
As a personal preference, I would suggest that everything an object needs to have in order to create valid state should be available within its constructor. If you have no way of providing valid state in a default constructor without invoking other methods defined in the object hierarchy, then get rid of the default constructor and put the onus on the users of your class to supply a valid String to your other constructor.
If you are ultimately just trying invoke the other constructor with the value of toString(), then I would suggest the following instead:
public Entity() {
name = toString();
}
which accomplishes the same goal you set out to achieve and properly initializes name.
As explained in the JLS this is not allowed before the instance is initialized.
However, there are ways to handle your scenario in a consistent manner.
As I see your case, you want to signify either a generated value (toString()) or a user provided value, which can be null.
Given this constraints, using TO_STRING_CONSTRUCTOR_ARGUMENT is failing for at least one specific use case, however obscure it may be.
Essentially you will need to replace the String with an Optional similar to what exists in Google Guava and will be included in Java 8, and seen in many other languages.
Having a StringOptional/StringHolder or whatever you choose, similar to this:
public class StringOptional {
private String value;
private boolean set = false;
public StringOptional() {}
public StringOptional(String value) {
this.value = value;
this.set = true;
}
public boolean isSet() { return set; }
public String getValue() { return value; }
}
Then you can call constructors with the knowledge of the inferred path.
public class Entity {
public Entity() {
this(New StringOptional());
}
public Entity(String s) {
this(new StringOptional(s));
}
private Entity(StringOptional optional) {
super(optional);
}
}
And store this for subsquent need:
if (optional.isSet() ? optional.getValue() : toString();
This is how I usually would handle a maybe-null scenario, hope it augments as an answer.
You cannot 'use' an instance that has not been created yet. By calling a second constructor you are postponing the creation, you cannot use it before the call or in the action of calling.
You can use a static method factory in your class Entity, and put the constructor private:
public class Entity {
private String name;
private Entity() {
}
public Entity(String name) {
this.name = name;
}
public static Entity createEntity() {
Entity result = new Entity();
result.name = result.toString();
return result;
}
}

Objectify, Key<T> is it possible? Work arounds?

What I mean by type is something that would allow me to do the following.
public class AnyObject{
List<this.type> list;
}
I know the following dosen't work.
public class AnyObject{
List<this.getClass()> list;
}
So how would I create a lets say a list, for example sake, of type of whatever this is?
--------------- UPDATE ---------------
I apologize I don't think I was clear. I seem to be getting that there is no way to escape type erasure, but if there is still away to solve my problem I will explain it better. Disclosure, this is more of an Objectify question. Sorry I have come to see that now.
Here we go, clear as I can ...
For every entity I plan to persist, in GAE datastore using Objectiy, I would like to have a method to generate an Objectify Key<?> using the id and parent field. Lets call this method generateKey(). here is how it looks.
public Key<MyEntity> generateKey() {
Key<MyEntity> key = Key.create(this.parent, MyEntity.class, this.id);
return key;
}
The problem is I have to write this exact code, more or less, for every entity I create. Actually, there is other repeated code, but my point can be made with this piece of repeated code alone.
So I tried this. I created a class called MyProjectEntity and have all my entitys extend it. Then implemented a generateKey() method using generics.
public abstract class MyProjectEntity<T, Y> {
#Id Long id;
#Parent Key<T> parentKey;
public Key<Y> generateKey() {
Key<Y> key = Key.create(this.parentKey, this.getClass(), this.id);
return key;
}
}
Then I extended all my entity classes with this new class I created called MyProjectEntity. Like such ...
#Entity
public class MyEntity extends MyProjectEntity<MyEntityParent> {...}
Sounds good, now all my entity will have a generateKey() method, well this didn't quite work. Objectify yelled at me and said IllegalArgumentException, can not declare Key of type T.
Then I tried Key<Object>, Objectify was still unpleased, Objectify said Object is not a registered entity. Should I register Object!?!? and that kinda loses the whole point to a typed key that Objectify offers.
Is there a good solution. Thanks!
-- UPDATE 2 --
Since someone pointed out Key.create(myEntity) I should point my full use ...
/**********************************************************************************************************************
* Constructors END & Identification and Relationship Methods BEGIN
**********************************************************************************************************************/
#ApiSerializationProperty(name = "id")
public String getWebSafeKey() {
String webSafeKey = getKey().getString();
return webSafeKey;
}
public void setWebSafeKey(String webSafeKey) throws BadRequestException {
try {
Key<MyEntity> key = Key.create(webSafeKey);
setKey(key);
} catch (IllegalArgumentException illegalArgumentException) {
throw new BadRequestException(ErrorMessage.INVALID_ID);
}
}
#ApiSerializationProperty(name = "parentId")
public String getParentWebSafeKey() {
String webSafeKey = parent.getString();
return webSafeKey;
}
public void setParentWebSafeKey(String parentWebSafeKey) throws BadRequestException {
if (id == null) {
try {
parent = Key.create(parentWebSafeKey);
} catch (IllegalArgumentException illegalArgumentException) {
throw new BadRequestException(ErrorMessage.invalidParentId("Property"));
}
} else {
/* Do nothing. Only set parent here if setWebSafeKey is never called, such as during a create. */
}
}
#ApiSerializationProperty(ignored = AnnotationBoolean.TRUE)
public Key<MyEntity> getParentKey() {
return parent;
}
public void setParentKey(Key<MyEntity> parentKey) {
this.parent = parentKey;
}
#ApiSerializationProperty(ignored = AnnotationBoolean.TRUE)
public Key<MyEntity> getKey() {
Key<MyEntity> key = Key.create(parent, MyEntity.class, id);
return key;
}
public void setKey(Key<MyEntity> key) {
id = key.getId();
parent = key.getParent();
}
public boolean webSafeKeyEquals(String webSafeKey) {
boolean equals;
if (id !=null & parent !=null) {
equals = getWebSafeKey().equals(webSafeKey);
} else {
equals = false;
}
return equals;
}
/**********************************************************************************************************************
* Identification Methods END & Other Getters and Setters BEGIN
**********************************************************************************************************************/
All this has to be inserted for every entity I create with MyEntity replaced for the actual entity name. It's not just typing. This code doesn't belong in the entity class, but rather in some abstract parent. If I could have only code unique to a particular entity in the class, my model would be cleaner, and easier to expand. Thanks again.
This would not make sense. Consider: you would never know what the type of list is. Suppose that list is used in some method of some class, it could always be that this is an instance of a subclass. So the parameter of List in the type of list can never be assumed in any code. If it can never be known, then what is the point of it? You would just use List<?>.
Generics is a purely compile-time thing. Therefore, it is meaningless to depend on the runtime class of something.
I suggest that you have
public class AnyObject<T> {
List<T> list;
}
and any class Foo which wants to have list be a List<Foo>, for example, should just implement or inherit from AnyObject<Foo>.
This does not make sense List<this.getClass()> list; as the type parameters are compile time thing in java. This information is erased at runtime.
Without being familiar with Objectify, just generics, the thing I see is that Key.create is supposed to itself take a generic argument <T> for the type of returned Key. So you would be supposed to do the following when you call the method in the superclass:
Key<Y> key = Key.<Y>create(this.parentKey, this.getClass(), this.id);
You may only simply have to do that to fix the error (and should be doing it anyway). Otherwise Key.create will try to instantiate a new Key<Y> and although it is more or less valid to not declare a type argument when a method asks for one, apparently Key.create may not like that.
I think you should also take another look at your Ts and Ys because it appears you are mixing them. Right now you are handing Key.create a Key<T> as a parameter but wanting to return a Key<Y>. Also if you declare your class as having <T, Y> it should be illegal to extend it with only <MyEntityParent>.
Looking at your code I think what you are trying to do is create Key of the same class as the method you are calling it from. IE class generateKey in MyEntity should return a Key<MyEntity>. I think the proper way to do this would be like so (which is valid):
public abstract class MyProjectEntity<T, K> {
Long id;
Key<K> parentKey;
public Key<K> generateKey() {
return Key.<K>create(parentKey, this.getClass(), id);
}
}
public class MyEntity extends MyEntityParent<MyEntityParent, MyEntity> {
/*
* K is now MyEntity and parentKey is a Key<MyEntity>
* generateKey now does the following:
*
* public Key<MyEntity> generateKey() {
* return Key.<MyEntity>create(parentKey, MyEntity.class, id);
* }
*
*/
}
It just seems like your example that doesn't work is giving the error because you aren't declaring the types properly. But it is hard to tell because it is unclear what your T and Y are supposed to be. You only show one of the types being declared and at least in your generateKey method you are handing Key.create a Key<T> but wanting to return a Key<Y>.
Or perhaps you should take a look at Registering Entities in the Objectify API. IE it seems you might be supposed to do something like this and that is a possible reason you are getting the error:
static {
ObjectifyService.register(MyEntityParent.class);
}
But anyway in the world of Java generics you really ought to be able to do something like this without any gymnastics unless something else is going on. The nature of erasure is that you can't find out the type at runtime but the type is essentially "known" because all instances of T are replaced with the argument type.
public abstract class MyProjectEntity<T> {
Key<T> parentKey;
}
becomes
public class MyEntity extends MyProjectEntity<MyEntityParent> {
Key<MyEntityParent> parentKey;
}
You can't find out whether or not parentKey is of Type <MyEntityParent> but it is of that type. You can obviously see this with something like a java.util.List where if you do the following:
List<Double> doubleList = new ArrayList<Double>(0);
doubleList.add("a string");
You will get the following if you ignore the compiler errors and try to run the program anyway:
Uncompilable source code - Erroneous sym type: java.util.ArrayList.add
java.lang.RuntimeException: Uncompilable source code - Erroneous sym type: java.util.ArrayList.add
Because the list does "only hold" instances of Double. This situation could be compared to an anonymous class where that instance of an ArrayList's add method now officially takes a Double as an argument. It is uncompilable because I just tried to do this:
public void add(Double element) {
// add the element to the array
}
list.add("a string");
Which is obviously illegal. This ArrayList's underlying array is still an Object[] but the methods will be changed to reflect the type and safely make sure the array only holds Double elements at runtime.
So I would recommend taking a look at the things I mentioned because it appears that there's more than one problem unless you've omitted relevant code.
I think I understand your problem and here is how you could do it. The trick is to pass the subclass as a generic parameter of the parent class:
class Parent<T> {
T doStuff() {
T res = null;
// res = ..... this.getClass() is ok...
return res;
}
}
public class SelfGerenic extends Parent<SelfGerenic> {
}
public class OtherSubClass extends Parent<OtherSubClass> {
}
If I got you right, you're looking for something like this:
public class Test {
private int id;
public Key<Test> getKey() {
return createKey(id, this.getClass());
}
public static <T> Key<T> createKey(int id, Class<? extends T> clazz) {
return new Key<T>(clazz, id);
}
private static class Key<T> {
private final Class<? extends T> clazz;
private final int id;
private Key(Class<? extends T> clazz, int id) {
this.clazz = clazz;
this.id = id;
}
private int getId() {
return id;
}
private Class<? extends T> getClazz() {
return clazz;
}
}
public int getId() {
return id;
}
}
It is not possible to replace Test here: public Key<Test> getKey() {!
This is because getKey() always returns Key. It can not return Test.
So basically no, there is no way to change this behaviour. Also there is no way to get the generic type of the "current" class. This is some kind of limit of the java generics :P
You could remove the generics here, so you do not have to implement getKey() every time.
public class Test {
private int id;
public Key getKey() {
return createKey(id, this.getClass());
}
public static Key createKey(int id, Class clazz) {
return new Key(clazz, id);
}
private static class Key {
private final Class clazz;
private final int id;
private Key(Class clazz, int id) {
this.clazz = clazz;
this.id = id;
}
private int getId() {
return id;
}
private Class getClazz() {
return clazz;
}
}
public int getId() {
return id;
}
}

How do I reimplement valueof on enumeration

I need to re-implement the enum.valueof method of a few of my enumerations so they no longer throw exceptions, instead they simply return null if a value doesn't exist in the enumeration.
I'm trying the basic
#Override
public static <T extends Enum<T>> T valueOf(Class<T> enumType,
String name){
but it's not working, saying I need to override or implement a super type.
I can come up with a super class I guess, but I'm just not sure how to put this together. Any ideas?
You can't. You'll have to define another, different method. The valueOf method is automatically generated by the compiler.
public static MyEnum permissiveValueOf(String name) {
for (MyEnum e : values()) {
if (e.name().equals(name)) {
return e;
}
}
return null;
}
Use Apache Commons Lang:
MyEnum myEnum = EnumUtils.getEnum(MyEnum.class, "MY_ENUM_VALUE");
Quote from the Javadoc for EnumUtils.getEnum:
Gets the enum for the class, returning null if not found.
This method differs from Enum.valueOf(java.lang.Class,
java.lang.String) in that it does not throw an exception for an
invalid enum name.
Is it absolutely necessary that the method is called valueOf like the method that enums have automatically? In the project that I'm currently working on we have similar methods, but we call them differently; for example, forName:
public static ESomeEnum forName(String name) {
for (ESomeEnum e : ESomeEnum.values()) {
if (e.name().equals(name)) {
return e;
}
}
return null;
}
You don't have to override valueOf. Here's what I did:
I had to "parse" some strings to enums and they didn't match with their declaration names, so I did a sort of reimplementation of valueOf(String name).
public enum Command {
DIR("DIR"),
PUT("PUT"),
GET("GET"),
OK("OK"),
ERROR("ERROR"),
READY("READY"),
FIN("#FIN#");
private String name;
private Command(final String name) {
this.name = name;
}
/**
* Returns the desired Enum or throws an exception
* #param commandName - String with the name contained by the Enum that you want
* #return Command
*/
public static Command getEnum(String commandName){
// if the string is "#FIN#" returns Command.FIN.
if(FIN.toString().equals(commandName)){
return FIN;
}
// if the name matches any of the remaining enums return whichever one matches
else if(Arrays.asList(Command.values()).contains(Command.valueOf(commandName))){
return Command.valueOf(commandName);
}
// if it still wasn't found, throw an exception
throw new IllegalArgumentException("No enum defined for this string: " + commandName);
}
#Override
public String toString(){
return name;
}
}
This code is tested and works.
You can use like:
Command k = Command.getEnum("#FIN#");
System.out.println(k.name() + " " +k.toString());
k = Command.getEnum("PUT");
System.out.println(k.name() + " " +k.toString());
And it's output would be:
FIN #FIN#
PUT PUT
Hope it helps.
You might consider creating a new (different name such as convert) static method in your enum classes.
public enum MyEnum{
....
public static MyEnum convert(Object value){
...
}
}

Categories

Resources