Ok, so in Java this is possible:
import org.eclipse.emf.common.util.Enumerator;
public enum MyEnum implements Enumerator {
LITERAL1(0, "Name", "Literal", "custom1", "custom2", "custom3"),
LITERAL2(0, "Name", "Literal", "custom1", "custom2", "custom3"),
LITERAL3(0, "Name", "Literal", "custom1", "custom2", "custom3"),
LITERAL4(0, "Name", "Literal", "custom1", "custom2", "custom3");
public static final int LITERAL1_VALUE = 0;
public static final int LITERAL2_VALUE = 1;
public static final int LITERAL3_VALUE = 2;
public static final int LITERAL4_VALUE = 3;
private static final MyEnum[] VALUES_ARRAY =
new MyEnum[] {
LITERAL1,
LITERAL2,
LITERAL3,
LITERAL4,
};
public static final List<MyEnum> VALUES =
Collections.unmodifiableList(Arrays.asList(VALUES_ARRAY));
private final int value;
private final String name;
private final String literal;
private final String custom1;
private final String custom2;
private final String custom3;
private MyEnum(int value, String name, String literal,
String custom1, String custom2, String custom3) {
this.value = value;
this.name = name;
this.literal = literal;
this.custom1 = custom1;
this.custom2 = custom2;
this.custom3 = custom3;
}
/*Getters for all of them*/
This is what's called an extended enum. I know it works - I tried and used it lots before. I know there could be discussion if this is what you should do with an enumeration - I think yes, as you still have your defined constants, but they just contain some more information (which is still sort of constant). (Also: I looked at this one, Custom fields on java enum not getting serialized, and I think they also follow my thinking in how to generate custom properties on enums).
Now, how on earth am I supposed to generate something like this from an Eclipse EMF model? I don't even know where to add extra properties to my enums in the .ecore model editor... I tried adding the extra properties as an annotation to ExtendedMetaData, which contains keys for all the custom properties. However when generating a .genmodel file that doesn't change the file (I know as I'm holding it against an earlier checked-in version in SVN, and SVN tells me nothing's changed). Ofcourse that also makes that there's no change in the generated model code.
Anyone? I know I can change generated model code by hand, but in the event I might change something to the model I'd lose those edits, that's obviously not what I'd want.
Thanks!
Update: Just to be all clear, this is how my .ecore looks like in the model editor:
MyEnum (EEnum)
LITERAL1 (EEnum Literal)
ExtendedMetaData (EAnnotation)
custom1 -> custom1
custom2 -> custom2
custom3 -> custom3
LITERAL2 (EEnum Literal)
ExtendedMetaData (EAnnotation)
custom1 -> custom1
custom2 -> custom2
custom3 -> custom3
LITERAL3 (EEnum Literal)
ExtendedMetaData (EAnnotation)
custom1 -> custom1
custom2 -> custom2
custom3 -> custom3
LITERAL4 (EEnum Literal)
ExtendedMetaData (EAnnotation)
custom1 -> custom1
custom2 -> custom2
custom3 -> custom3
Anyone? I know I can change generated model code by hand, but in the event I might change something to the model I'd lose those edits, that's obviously not what I'd want.
In fact, you can add your extended enum the way you always do. When your genmodel generates code from your model it adds a tag #generate to know which pieces of code have been created by it. If you add a piece of code, it would not have this flag. Then, if you need to update your model and so your generated code, EMF just modifies the pieces of code that have the #generated tag. In this way it will respect your code insertion and you will not lose what you have done.
For more information, you can search on the Eclipse Modeling Framework book wrote by Budinsky and company. I quote what the book says (p. 25):
You are expected to edit the generated classes to add methods and instance variables. You can always regenerate from the model as needed and your addition will be preserved during the regeneration. [...] Any method that doesn't have this #generated tag (that is, anything you add by hand) will be left alone during regeneration. If you already have a method in a class that conflicts with a generated method, then your version will take precedence and the generated one will be discarded.
Related
I have an old doubt about constants in Java Projects maintenance. From my perspective, when we try putting the constants inside an Abstract class like that:
public final class MyConstants {
public static final String CONSTANT1 = "const1";
public static final String CONSTANT2 = "const2";
public static final String CONSTANT3 = "const3";
public static final String CONSTANT4 = "const4";
}
after that using those constants inside classes in the project:
public void myMethod(final Map params) {
final String myparam = (String) params.get(MyConstants.CONSTANT1);
//DO SOMETHING WITH PARAMS
}
It leads to boiler plate code, verbose use of constants and no real advances. In other hand if we put those constants inside the class for somehow people don't like it. They say "what about we have the same constant declare somewhere?" the problem is maintainance issues, if we change those constants in that class the change can be visible on several parts without any big problem.
Those constants are mainly used for mapping webservices for java perspective without having to generating POJOs like JAXB based on WSDL, the webservices operations are mapped directly for key value maps in Java.
I want to know what do you think about this approach and if we have any other choice.
Thank you.
If I understand your concern, don't hardcode those constants as values except perhaps as defaults and store them with Properties and/or ResourceBundle(s). You might also read the Java Tutorial on Properties. Something like,
Properties props = new Properties();
FileInputStream in = new FileInputStream("my.proprties");
props.load(in);
String v = props.get("CONSTANT_ONE", "const1"); // <-- the "1" is a default.
Then if you need to change the property later you only have to modify the properties file.
I know that TableViews and their columns depend on the fact that the represented objects have XYZProperty values and appropriate getters. Do I HAVE to use all that notation though? My particular class has a lot of fields as is, and uses a builder pattern too. Why can't I just stick with the original field variables rather than creating XProperty versions?
class ActionItem{
private String referenceNum;
private int percentComplete;
private ActionPlan actionPlans;
private LocalDate dateAssigned, dateDue, dateFinal, dateStarted,
dateCompleted;
private String subject, description;
private Employee assignedBy, assignedToPrimary, assignedToSecondary;
private EmployeeGroup assignedToGroup;
private Criticality criticality;
private Status status;
----
private SimpleStringProperty referenceNumberProperty = new SimpleStringProperty();
private SimpleIntegerProperty percentCompleteProperty = new SimpleIntegerProperty();
private SimpleObjectProperty<ActionPlan> actionPlansProperty = new SimpleObjectProperty<ActionPlan>();
private SimpleObjectProperty<LocalDate> dateAssignedProperty = new SimpleObjectProperty<LocalDate>();
private SimpleObjectProperty<LocalDate> dateDueProperty = new SimpleObjectProperty<LocalDate>(),
dateFinalProperty = new SimpleObjectProperty<LocalDate>(),
dateStartedProperty = new SimpleObjectProperty<LocalDate>(),
dateCompletedProperty = new SimpleObjectProperty<LocalDate>();
private SimpleStringProperty subjectProperty = new SimpleStringProperty(),
descriptionProperty = new SimpleStringProperty();
private SimpleObjectProperty<Employee> assignedByProperty = new SimpleObjectProperty<Employee>(),
assignedToPrimaryProperty = new SimpleObjectProperty<Employee>(),
assignedToSecondaryProperty = new SimpleObjectProperty<Employee>();
private SimpleObjectProperty<EmployeeGroup> assignedToGroupProperty = new SimpleObjectProperty<EmployeeGroup>();
private SimpleObjectProperty<Criticality> criticalityProperty = new SimpleObjectProperty<ActionItem.Criticality>();
private SimpleObjectProperty<Status> statusProperty = new SimpleObjectProperty<ActionItem.Status>();
}
Does calling upon a getter method perform faster than trying to pull the object out of the SimpleProperty?
You can pretty much use any design you like.
The FX property pattern gives you a lot of functionality: it creates observable, writable, properties that in many cases can be wired directly into controls. So if you design your "table beans" using that pattern, then you can use the PropertyValueFactory as your cellValueFactory, and lots of stuff happens "automagically", such as updating table cells when the value changes, and vice-versa.
Using properties themselves doesn't add much overhead. There's a nice document that outlines some good practices for using FX properties.
The PropertyValueFactory, though, I think does add some overhead, as it relies on reflection to find the property from a specified name. So you will see some (I don't promise how much) benefit if you replace
myTableColumn.setCellValueFactory(new PropertyValueFactory<>("thing"));
with
myTableColumn.setCellValueFactory(new Callback<CellDataFeatures<S,T>, ObservableValue<T>>() {
public ObservableValue<T> call(CellDataFeatures<S,T> data) {
return data.getValue().thingProperty() ;
}
});
(or, in Java 8, the much simpler
myTableColumn.setCellValueFactory(data -> data.getValue().thingProperty());
).
Now, if you don't need the bells and whistles of the JavaFX properties (for example, the values in the table row items won't be changed external to editing in the table, and the editing in the table needs to be "hard-wired" via a setOnCommit(...) anyway), then you can save the (small) overhead of the JavaFX properties by omitting them and just using the regular Javabean model, with getX() and setX(...) methods. There's some, though I think not much, performance benefit, and obviously less code.
The overhead from the reflection in the PropertyValueFactory is (my guess) larger than the overhead from using JavaFX properties, so if you're looking to do this for performance reasons, I would also explicitly wire the callback to the get method, instead of relying on the PropertyValueFactory. As in the link in #brian 's comment, some previous versions were highly inefficient in implementing that (though this is now fixed). So something like
class Item {
private String name ;
public String getName() {
return name ;
}
public void setName(String name) {
this.name = name ;
}
}
TableColumn<Item, String> nameCol = new TableColumn<>("Name");
nameCol.setCellValueFactory(itemData -> new ReadOnlyStringWrapper(itemData.getValue.getName()));
is probably about as efficient as it gets: again though, if you want your table editable, you need to wire editing commits to calls to setName(...) by hand, and updates to the data external to the table won't be reflected in the table.
Bottom line: if you don't want to use JavaFX properties, you don't have to. You miss some free functionality, and there are ways to code that in yourself, and you might get some (slight) performance benefit as well as saving some code. The one case that's really hard to work around is updating properties displayed in the table, externally from table editing. If you are doing that in your code, JavaFX properties make your life a lot easier.
Update:
Based on your comments, I would recommend using JavaFX properties for your use case. I strongly recommend reading the document linked above, slides 18-46, and especially the property patterns on slides 30-43.
In particular, though, use the abstract class (e.g. StringProperty) as the type for your property, not the concrete type (SimpleStringProperty), and when using properties as properties of objects, instantiate them with a name and reference to their bean. For example:
private StringProperty referenceNumberProperty = new SimpleStringProperty(this, "referenceNumber");
public final StringProperty referenceNumberProperty() {
return referenceNumberProperty ;
}
public final String getReferenceNumber() {
return referenceNumberProperty.get() ;
}
public final void setReferenceNumber(String referenceNumber) {
this.referenceNumberProperty.set(referenceNumber);
}
Note that it's marginally more conventional not to include "property" as part of the reference name (i.e. private StringProperty referenceNumber instead of private StringProperty referenceNumberProperty), but of course that's totally up to you.
I would like to describe a nasty issue that occurs when making naive use of Java enums in the context of JPA entities. Let's take a look at how this problem can occur.
First the domain model:
Say I have an Text JPA entity that represents piece of text (novel, news article, etc.). Here is the JPA entity:
#Entity
public class Text {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Version
#Column(name = "version")
private Integer version;
private String content;
#Enumerated
#ElementCollection
private Set<Style> styles;
//Setters and getters omitted.
To an instance of Text, one or many styles can be applied such as italic, bold and so on. The style is represented as a java enum.
To start with, we assume that the application starts its life with the following enum:
public enum Style {
BOLD, ITALIC
}
The test below will then insert the following lines in a relational database:
Integration test:
#Test
#Rollback(value=false)
public void inEarlyLifePersist() {
Text text =new Text();
text.setContent("This is my beautiful novel...");
text.setStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
text.persist();
}
Data in text table:
# id, content, version
11, This is my beautiful novel..., 0
*Data in text_style table:*
# text, styles
11, 0
11, 1
Then, later on, some ill-advised developer decides to add a new style: STRIKE_THROUGH to our Style enum placing this new enum constant/value as the first one:
public enum Style {
STRIKE_THROUGH, BOLD, ITALIC
}
and then a new record is inserted in DB as follows:
#Test
#Rollback(value=false)
public void afterChangeToEnumPersist() {
Text text =new Text();
text.setContent("This is my beautiful short story...");
text.setStyles(EnumSet.of(Style.STRIKE_THROUGH, Style.BOLD));
text.persist();
}
In text table:
# id, content, version
14, This is my beautiful short story..., 0
And *in text_style table:*
# text, styles
14, 0
14, 1
Obviously, the domain model is seriously compromised now!
My question is what are the possible strategies to avoid spelling disaster in the domain as is the case above (other than the obvious solution to place the STRIKE_THROUGH enum constant after ITALIC)?
edit 1: Obviously I do not want to store strings (see EnumType.STRING) in my database for obvious performance reasons i.e. data retrieval and storage performance would be seriously affected!
You need to redefine your enum like below.
public enum Style {
STRIKE_THROUGH(2), BOLD(0), ITALIC(1)
Style(int code){
this.code=code;
}
}
And implement a Hibernate User type to persist the code.
There's an option (EnumType.STRING) to use the actual name of the enum value (the String returned by { name() } instead of the ordinal. That way you can reorganize your enum values, but then you are tied to the names of the enum values.
The ideal solution would be to be able to declaratively tell the JPA implementation to use an arbitrary property of the enum as the database identifier. But AFAIK, that it's not provided in the current JPA specs, it would be great to have such a feature in future JPA specs.
The answer by Sajan shows how to implement that using a Hibernate-specific feature.
The Enumerated annotation also knows a property that specifies the EnumType. Two types exist: EnumType.ORDINAL and EnumType.STRING. ORDINAL is the default one.
So, if you do it the following way
#Enumerated(EnumType.STRING)
you will see the enumeration names in the DB column (and not the ordinals). Of course, you are now vulnerable to name changes in your enumeration. You have to die one death, but I think, the names are better.
I can't see why people find the enum names more reliable than their ordinals. Actually, there are many good reasons for renaming enums (fixing typos, changed names due to politics or political correctness, etc.), but I can't see any good reason for reordering them.
Both renaming and reordering happens and the only thing which can help is a test. Unfortunately, the best test I can think of will fail on any change. Fortunately, the test can tell what happened and then be fixed easily.
public void testE1IsStable() {
assertEnumUnchanged(E1.class, 4, "bec419c8380dbe9ec3b86a7023a55107");
}
public void testE2IsStable() {
assertEnumUnchanged(E2.class, 3, "1e89e93c6cbdbb7311b814c19d682548");
}
private void assertEnumUnchanged(Class<? extends Enum<?>> enumClass, int expectedCount, String expectedHash) {
final Object[] enumConstants = enumClass.getEnumConstants();
if (expectedCount < enumConstants.length) {
final Object[] shortened = Arrays.copyOf(enumConstants, expectedCount);
assertEquals("Enum constants may be only appended! Ask balteo!",
expectedHash, hashAsString(shortened));
fail("An enum constant has been added! This test needs to be updated. Ask balteo!");
} else if (expectedCount > enumConstants.length) {
fail("Enum constants must not be removed! Ask balteo!");
} else {
assertEquals("Enum constants must not be reordered! If they get renamed, this test must be updated. Ask balteo!",
expectedHash, hashAsString(enumConstants));
}
}
private String hashAsString(Object[] enumConstants) {
final Hasher hasher = Hashing.md5().newHasher();
for (final Object o : enumConstants) hasher.putUnencodedChars(o.toString());
return hasher.hash().toString();
}
I'm looking for the best solution to store Java EE application's global data using Hibernate. It will consist of key value pairs. Example:
projectStarted = "10-11-11"
developerNumber = 3
teamLeader = "John"
As you see, all of this entries have different types.
For now I see two options:
1) Create GlobalData entity. Each field of it will be represented as unique column in the table and will contain unique setting. This way I have no problems with type casting, but I would like to avoid it in case where there will be big amount of settings.
2) Create Setting entity. Each of it will contain two fields: key(Primary key) and value and will be represented as unique record in the table. This is preferable solution, but It's seems to me that I will get a lot of type casting, because settings can be any type.
So basically, I'm looking for the way to implement second solution without getting a lot of troubles from different types. Can anybody help me?
Thanks.
Edit 1.
Yeah, thanks Christian. Just got similar idea.
What if I will have Settings entity, which will be like:
#Entity
#Table(name = "settings")
public class Setting {
#Column
private String key;
#Column
private String value;
#Column
private String converterClassFullName; //example by.lugovsky.MyConverter
//Getters, setters
}
And GlobalData class.
public class GlobalData {
private Date projectStarted;
private int developerNumber;
private String teamLeader;
Set<Setting> settings;
//Getters and setters for all, except settings.
}
So basically my idea is to convert Setting entity before persisting/updating/ etc. I can do this in my DAO, but I was wondering, if I could annotate GlobalData class with #Entity annotation as well without creating new table. This way I can set OneToMany annotation to Setting's set and Perform conversions in the internal #PrePersist etc. methods.
Will Hibernate allow me to do this?
Thanks again
You could store a Converter-Class into the db and the let it run through the given converter for a property before using the value. JSF offers Converter API:
public interface Converter{
public Object getAsObject(FacesContext fc, UIComponent component, String value) throws ConverterException;
public String getAsString(FacesContext fc, UIComponent component, Object obj) throws ConverterException;
}
If you have a schema with
name: String
value: String
converter: Class
then you could do something like this:
PropertyEntry pe = // Get from OR-Mapper
Converter c = (Converter) pe.getConverter().newInstance();
Object o = c.getAsObject(null, null, pe.getValue());
// use the object o instead of value
For even more coolness you could also define a field in the class which will not be persisted which you could use to hold the converted value within the object.
How will I be able to retrieve the value of a variable which has a dynamic name
For Example I have list of constants
public class Constant{
public static final String S_R = "Standard(240)";
public static final String S_W = "Standard(180)";
public static final String L_R = "Large(360)";
public static final String L_W = "Large(280)";
}
Based on database I build a variable name
String varName = "S" + "_" +"R"; // This can be S_R , S_W , L_R or L_W
String varVal = // How do i get value of S_R
Use a normal HashMap with variable names as strings against their values. Or use a EnumMap with enums as key and your value as values. AFAIK, that's the closest you can get when using Java. Sure, you can mess around with reflection but IMO the map approach is much more logical.
You can use a Map<String, String> and locate the value by its key.
Even better, you can have an enum:
public enum Foo {
S_R("Standard", 240),
S_W("Standard", 180),...;
private String type;
private String duration;
// constructor and getters
}
And then call Foo.valueOf(name)
(You can also do this via reflection - Constants.class.getField(fieldName) and then call field.get(null) (null for static). But that's not really a good approach.)
If you really must do this (and it's unlikely), you would have to use the Java "reflection" APIs.