Nested enum with definition as String - java

I'm facing a problem with nested enum. So, I have an nested enum which has default values as you can see. Before there were just an enums like CDs and CMs. Now I set something like definition to every of it as you can see "Cool Ds" and etc. Currently I'm facing a problem that I can't read enums String, which is in () and I don't know how to fix it anymore. Does anyone have an idea?
package com.test.beans;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
#JsonIgnoreProperties(ignoreUnknown = true)
public class RecordBean implements Serializable {
public enum Types {
CDs("Cool Ds"), CMs("Cool Ms");
private final String s;
private Types(String s) {
this.s=s;
}
public String getTypes(){
return s;
}
public static Types fromNumeric(int index) {
switch (index) {
default:
return null;
case 0:
return Types.CDs;
case 1:
return Types.CMs;
}
}
}
private Types type;
private float value;
public RecordBean() {
// default constructor for default instantiate
}
public RecordBean(Types type, float value) {
this.type = type;
this.value = value;
}
public Types getType() {
return type;
}
public void setType(Types type) {
this.type = type;
}
public float getValue() {
return value;
}
public void setValue(float value) {
this.value = value;
}
}
UPDATE
Error what I'm getting:
17/04/10 12:44:53 ERROR App$: Can not construct instance of com.test.beans.RecordBean$Types from String value 'Cool Ds': value not one of declared Enum instance names: CDs, CMs ]
So as you can see he is not comparing my String 'Cool Ds' with enums String in brackets but with pure enum or CDs and CMs
My USE-CASE is like this. I'm working spark streaming where data are incoming to my RecordBean class and where are comparing to my enum type. Because in database are changed types from CMs to Cool Ms I needed to change the same in my app by adding definition to Enum. Afterwards I couldn't accomplish part where app will process enum like CMs and read its definition or Cool Ms

Be sure, you can read with : CDs.getTypes() and CMs.getTypes()

Guessing: maybe the framework is calling toString() on your enum constants, thus you might want to add:
public enum Types {
...
#Overrride
public String toString() { return s; }
In other words: make sure that your existing enum constants are really using that "new" changed string name.
But beyond that: consider stepping back and changing your overall design. Your problem isn't uncommon - enums are nice from a programming point of view (as in: using enum constants leads to cleaner code); but: they are not suited for persistence. Versioning with enums is hell.

Related

How to work-around the restriction of primitive objects - like Integer, String - not being allowed to derive from?

I realize that it is not possible to derive from primitive objects as they are declared final. How do I work around this restriction? I am programming with the JPA Criteria API. Almost everywhere I handle with my own methods having Integer/String parameters to compare against entity fields representing database table row values. On any of these parameters I would like to accept QueryParameter<Integer> or QueryParameter<String>. Doing so I would have to create the method a second time accepting query parameters instead of the literals. However, thinking about value lists (as in the QueryBuilder's in(...) method) with permutating literals and query parameters, makes it hard or even impossible to implement.
Let us assume I had an entity Car with a method withFeatures(StringRepresentation ... features) and there would be literals and query parameters had derived from the same super-class StringRepresentation which itself would have be derived from the primitive type String. I would like to do so:
myCar.withFeatures("Seat Heating", "Metallic Color", "Trailer Hitch");
myCar.withFeatures(new QueryParam<String>("MyFavourit"));
myCar.withFeatures("Seat Heating", new QueryParam<String>("LoveThatColor"), "Trailer Hitch");
Has anyone an approach or even kind of a solution for this?
I'd use a builder pattern with one method for each type of criterion.
class Car {
private Set<String> features = new HashSet();
public Car withFeature(String f) {
features.add(f);
return this;
}
public Car withFeature(QueryParameter<String> q) {
features.add(q.getStringRepresentation()); // or whatever
return this;
}
...
}
So you can say:
myCar.withFeature("Seat Heating")
.withFeature(new QueryParam<String>("MyFavourit");
with permutating literals and query parameters, makes it hard or even impossible to implement
You could leverage CharSequence for strings, but I'm not sure that's a god idea...
import lombok.RequiredArgsConstructor;
public class Test {
public static void main(String[] args) {
withFeatures("test", new StringQueryParam("test2"));
}
#SafeVarargs
public final static <T extends CharSequence> void withFeatures(T ...params) {
// Wrap in StringQueryParam if not an instance of QueryParam<String>
}
interface QueryParam<T> {
}
#RequiredArgsConstructor
static class StringQueryParam implements QueryParam<String>, CharSequence {
private final CharSequence value;
#Override
public int length() {
return value.length();
}
#Override
public char charAt(int index) {
return value.charAt(index);
}
#Override
public CharSequence subSequence(int start, int end) {
return value.subSequence(start, end);
}
}
}
Having less verbose static factory methods (e.g. QueryParam.of, QueryParam.all, etc. for query params) mixed with builders or ways to combine them effectively could help.
e.g.
// Assuming Lists.union util method
withFeatures(Lists.union(
QueryParam.all("a", "b"),
QueryParam.of("c")
));
// With static imports
withFeatures(union(params("a", "b"), param("c"));
// With ParamsBuilder
withFeatures(ParamsBuilder.of("a", "b").add(QueryParam.of("c").build())));
Hopefully that gives you some ideas on how to design the API! You may as well use a more complicated, but flexible route where the entire criteria is just an AST so that QueryParam really just is a type of Expression in the AST allowing to create composites, etc. If you look at QueryDSL everything is a DslExpression and you have visitors to execute operations against the tree.
I spent some time to solve that problem taking in the hints from the Java Community so far.
Of course I am a follower of Java's concept of type safety (thanks to plalx). Hence, my solution will probably has to do with parameterized types.
And also I do admiring the concept of design patterns like many others (thanks to tgdavies). Hence, I use the builder pattern with one method for each type of criterion. I will accept to implement car feature methods for
using plain old literals of String
as well as specifying parameters of String
That is:
myCar.withFeatures("Seat Heating", "Metallic Color", "Trailer Hitch");
as well as specifying (let's say) query parameters or String parameters of some kind with a slightly more complex way by using a static method sp(...)
myCar.withFeatures(sp("MyFavourit"));
and of course a mixture of both, introducing another static method sr(...) for string representation:
myCar.withFeatures(sr("Seat Heating"), sp("LoveThatColor"), sr("Trailer Hitch"));
The mixture of both is important in cases where we want to use variable arguments in method signatures to specify those representations, in this case car features.
As one can see, it is almost the usage I stated above when posting this question.
How can I achieve this?
At first I designed an interface to implement my different String representations against:
public interface ValueTypeRepresentation<T> {
public Class<T> getClazz();
public QueryParameter<T> getQueryParameter();
public RepresentationType getRepresentationType();
public T getValue();
}
The methods are to determine whether the representation is a literal or a parameter, and to get the literal's value resp. the parameter itself to later on use its name.
The clazz member is to ease the Java Generic Type Inference purposes because I will be using parameterized types to implement different type representations. As I said, String ist just the starter of the show.
Then I designed an abstract class to derive the concrete classes of representations of different primitive objects from:
abstract class AbstractValueTypeRepresentation<T> implements ValueTypeRepresentation<T> {
private Class<T> clazz;
private RepresentationType representationType = RepresentationType.VALUE;
private QueryParameter<T> queryParameter;
private T value;
public AbstractValueTypeRepresentation(Class<T> clazz, T value) {
this.clazz = clazz;
this.representationType = RepresentationType.VALUE;
this.value = value;
}
public AbstractValueTypeRepresentation(QueryParameter<T> qp) {
this.clazz = qp.getClazz();
this.representationType = RepresentationType.PARAM;
this.queryParameter = qp;
}
#Override
public Class<T> getClazz() {
return clazz;
}
#Override
public QueryParameter<T> getQueryParameter() {
return queryParameter;
}
#Override
public RepresentationType getRepresentationType() {
return representationType;
}
#Override
public T getValue() {
return value;
}
}
To distinguish a literal of that type from the query parameter of that type, I introduced this enumeration:
public enum RepresentationType {
PARAM, VALUE;
}
Then I designed the first concrete representation, here for my StringRepresentation (derived from the abstract class above):
public class StringRepresentation extends AbstractValueTypeRepresentation<String> {
public static StringRepresentation sr(String s) {
return new StringRepresentation(s);
}
public static StringRepresentation sp(String name) {
return new StringRepresentation(new QueryParameter<String>(String.class, name));
}
public StringRepresentation(String value) {
super(String.class, value);
}
public StringRepresentation(QueryParameter<String> queryParameter) {
super(queryParameter);
}
}
Obviously this is easy to extend to representations of Integer, Float, LocalDate, etc.

How to serialize and deserialize multi argument enum in Java using JPA 2.1 or lower (Postgres)

public enum CameraType {
CAMERA(false, false, "External lens ", ""),
CameraType{
boolean collector,
boolean hidden,
String description
) {
this.collector = collector;
this.granular = hidden;
this.description = description;
} // end ctor
public void setHide(boolean hidden) {
this.hide = hidden;
}
} // end enum
I have few Instance of CameraType.
I have a setter for "hidden" property which on certain condition is set to true or false.
Now I serialize CameraType with few other fields inside SecurityEntity.
```
#Entity
#Table
public class Security {
Few more fields...
#Enumerated(EnumType.STRING)
#Column(nullable = false)
private CameraType cameraType
And other fields...
}
```
When I deserialize the value of "hidden" field is always false. If I understand correctly, during deserialization ctor is called and default is assigned.
Is there a way I can retain the value of "hidden" field(true or false) after deserialization per instance of CameraType.
I am using Postgres DB 10.
enter code here
Please Please help. I am out of clues.
By definition, enums are immutable elements of a fixed set. Because of this, to represent an enum value you just need its name. That's exactly what JPA does during serialization/deserialization.
You are trying to violate the rules. While Java allows you to treat enums almost as plain objects, JPA treats them according to what they are supposed to be. That's why your code is not working.
You can either:
make CameraType into a class and serialize it as such, or
split CameraType into two parts, for example enum CameraType (immutable) and class CameraConfig (with all the mutable fields)
The former answer is correct : enums must be immutable and dividing parts into immutable and mutable data is a good choice.
One addition here: using the enum values for database storage is often not a good choice, because when another developer decides to refactor the enum names and you are after this reading old entries from database, you got a crashing application...
So I would suggest to use javax.persistence.AttributeConverter to deserialize/serialize an enum in a specific and rename save way.
Here a very simple example with an enum called MyDefinition:
enum MyDefinition{
ONE("def_one"),
TWO"def_two"),
THREE("def_three"),
;
private String id;
private MyDefinition(String id){
this.id=id;
}
public String getId(){
return id;
}
public static MyDefinition fromId(String id) {
for (MyDefinition definition : MyDefinition.values()) {
if (definition.id.equals(id)) {
return definition;
}
}
return null;
}
}
Here the converter:
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
#Converter(autoApply = true)
public class MyDefinitionAttributeConverter implements AttributeConverter<MyDefinition, String> {
#Override
public String convertToDatabaseColumn(MyDefinition attribute) {
if (attribute == null){
return null;}
}
return attribute.getId();
}
#Override
public MyDefinition convertToEntityAttribute(String dbData) {
return MyDefinition.fromId(dbData);
}
So we can use the ids for database. A renaming of the enum names will no longer lead to a crashing application when reading old data.

Enum, How to rename during (de)serialization?

Hi is it possible to change name of ENUM in Java?
For example, I have enum -
public enum CloudType {
AZURE, OPENSTACK
}
And a class -
public class Env{
private CloudType cloudType;
}
And during JACKSON parsing, if I give -
{
"cloudType":"AZURE"
}
Or
{
"cloudType":"azure"
}
It will give me an Env object with cloudType=AZURE ?
One thread is there (Jackson databind enum case insensitive), but really we need to do this much?
Or
#XmlEnumValue("azure")
AZURE("azure"),
will be enough?
You can decouple the Java names of the enum instances from their JSON representations.
You should add a #JsonValue-annotated method to your enum CloudType to tell Jackson which value to use when reading/writing JSON.
For that you also need a constructor to initialize this value.
Like this:
public enum CloudType {
AZURE("azure"),
OPENSTACK("openstack");
private final String value;
private CloudType(String value) {
this.value = value;
}
#JsonValue
public String getValue() {
return value;
}
}
Then Jackson will serialize CloudType.AZURE to "azure",
and deserialize "azure" to CloudType.AZURE.

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

Emulate C++ enum integer with Java Enums

I'm attempting to translate some C++ code into Java. I'm looking for the best way to emulate this type of C++ paradigm in Java -- I think enums are probably the answer but I'm open to anything
C++ code:
typedef UInt32 Type;
enum { UNKNOWN, QUIT, SYSTEM, TIMER, LAST }
...
Type newType = UNKNOWN;
Type nextType = LAST + 1;
...
// "Register" the new type
newType = nextType;
nextType++;
...
switch (newType) {
case UNKNOWN:
case QUIT:
...
case LAST:
// Ignore unset or predefined types
default:
// Some type other than the predefined. Do something special
Essentially I'm looking for a way to "expand" the values of a Java enumeration.
enum Type { UNKNOWN, QUIT, SYSTEM, TIMER, LAST }
doesn't quit cut it.
I like the idea of making a new object for strong typing.
Again, I'm looking for the best pattern to use here. I could easily float by with a few public static final int UNKNOWN, etc
One advantage of Java enums is, that they are essentially objects like all others. In particular, you can have methods on the constants, and make your enum implement interfaces:
interface Useful {
void doStuff();
}
enum Foo implements Useful {
DEFAULT {
public void doStuff() {
...
}
},
MAGIC {
public void doStuff() {
...
}
}
}
So, instead of taking arguments of the enum type, your methods could accept any implementation of the interface, and in particular, provide the default stuff by having the enum constants implement whatever is necessary.
They can also have members:
enum Explicit {
FIRST(0), SECOND(1), THIRD(2);
private final int value;
private Explicit(int v) {
this.value = v;
}
}
Note, that constants have an internal numeric value (reflecting the position of the constant among its peers) which is accessible using the ordinal method:
assert Explicit.FIRST.ordinal() == 0;
But relying on this is a little bit dangerous. If you are going to (say) persist enum constants in a database, then the following change would break the code:
enum Explicit {
FIRST(0), NEWELT(-1), SECOND(1), THIRD(2);
private final int value;
private Explicit(int v) {
this.value = v;
}
}
when using ordinal values. For this reason, the serialization machinery uses the constant's name instead of its position when serializing enum values.
So:
Type.X + 1
would be
Enum.values()[Enum.X.ordinal() + 1]
and the switch could be modelled using interfaces implemented by the enum itself (you can use enums in switch statements in Java, but often, making the enum implement the necessary code yields more maintainable code)
If each value of Type is just an int, then I'd probably go for a bunch of static final ints in a class.
Just for the record, something like this works more or less type-safely. I can't determine if the complexity is warranted without knowing more about the problem.
public class abstract Type
{
public static final Type UNKNOWN = registerStd("UNKNOWN");
...
public static final Type TIMER = registerStd("TIMER");
// use this to keep track of all the types
private static final List<Type> REGISTERED = ...
//This will do your switch statement for you, implemented by
// anonymous subclasses
public abstract void dispatch(Type onMe);
// here's how you make the standard ones
private static Type registerStd(String name)
{
Type heresOne = new Type(name)
{
// note, it's a no-op
public void dispatch(DoStuffer algorithm) {}
};
REGISTERED.add(heresOne);
return heresOne;
}
//here's how you make the non-standard ones
public static Type registerNew(String name)
{
Type heresOne = new Type(name)
{
public void dispatch(DoStuffer algorithm) {algorithm.execute(this)}
};
REGISTERED.add(heresOne);
return heresOne;
}
}
public interface DoStuffer
{
public void execute(Type onMe);
}
//Then your code becomes
Type newType = Type.registerNew("NewType");
newType.dispatch
(
new DoStuffer()
{
public void algorithm(Type forMe) { ... }
}
);
Maybe this is a little esoteric. But it does allow for "easy dispatch" at the caller site and an extensible enum, in some sense.

Categories

Resources