what is Java best practice to handle enum's - java

hi I know Java for a long time and recently I have been diving deep to the Java world.
As an experienced c# developer I find it odd to use Java enum's.
For example if I show on console items such as :
public enum AdminOpertionFirstlayer
{MANAGE_SUPPLY,
MANAGE_CUSTOMERS_SERVICE,
ORDERS_MANAGEMENT,
REPORTING_OPRATIONES}
I find it hard to write them down to the user , cause I have to define new varible
*AdminOpertionFirstlayer []adminOpertionFirstlayerArr =
AdminOpertionFirstlayer.values();
in order to achieve this :
for (int i = 0; i < adminOpertionFirstlayerArr.length; i++) {
String s = String.format("%d. %s",
i+1,
adminOpertionFirstlayerArr[i].toString());
Screen.print(s);
}
AdminOpertionFirstlayer chosen= adminOpertionFirstlayerArr
[(Integer.parseInt(dataIn.readLine()))-1];
But I feel it's a bad practice to declare on *
Is there a best practice (enum extension is one ... ) ?
Is there TryParse available or every time I parse I should try and catch ?
thank you
EDIT
does doing this is understandable and readable ?
public enum MainMenuOptiones{
ADMIN {public void secondLayerMenu(){
Main.AdminSecondLayerMenu();}},
CUSTOMER{public void secondLayerMenu(){
Main.customerSecondLayerMenu();}},
EXIT{public void secondLayerMenu(){
System.exit(1);}},
UNAPPLICABLE{public void secondLayerMenu(){
Screen.printToScreen("chice doesnt exist try again");}};
abstract public void secondLayerMenu();
}
the phrphes is instead of using all the switch mechanism
I can use
enumInstance.secondLayerMenu();

You could use Java's enhanced for loop (and the ordinal value for the enum)
for (AdminOperatorFirstLayer operator : AdminOperatorFirstLayer.values()) {
String s = String.format("%d. %s", operator.ordinal(), operator);
Screen.print(s);
}
Then you can use the ordinal value to recreate the enum:
AdminOperatorFirstLayer chosen =
AdminOperatorFirstLayer.values()[(Integer.parseInt(dataIn.readLine()))];
Or you could use the name:
for (AdminOperatorFirstLayer operator : AdminOperatorFirstLayer.values()) {
String s = String.format("%s. %s", operator.name(), operator);
Screen.print(s);
}
Then you can use valueOf value to recreate the enum:
AdminOperatorFirstLayer chosen =
AdminOperatorFirstLayer.valueOf(dataIn.readLine()];

The Enum<E> class is the base for all enums in Java.
There's no need to declare a variable with values, use an enhanced for loop to print them out if you want the users to read your source code.
Generally you want to print out a localised string rather than the name of the enum in the source.
There isn't an equivalent to TryParse, instead use AdminOpertionFirstlayer.valueOf(AdminOpertionFirstlayer.class, string) and catch the IllegalArgumentException.

Related

java enum string matching

I have an enum as follows:
public enum ServerTask {
HOOK_BEFORE_ALL_TASKS("Execute"),
COPY_MASTER_AND_SNAPSHOT_TO_HISTORY("Copy master db"),
PROCESS_CHECKIN_QUEUE("Process Check-In Queue"),
...
}
I also have a string (lets say string = "Execute") which I would like to make into an instance of the ServerTask enum based on which string in the enum that it matches with. Is there a better way to do this than doing equality checks between the string I want to match and every item in the enum? seems like this would be a lot of if statements since my enum is fairly large
At some level you're going to have to iterate over the entire set of enumerations that you have, and you'll have to compare them to equal - either via a mapping structure (initial population) or through a rudimentary loop.
It's fairly easy to accomplish with a rudimentary loop, so I don't see any reason why you wouldn't want to go this route. The code snippet below assumes the field is named friendlyTask.
public static ServerTask forTaskName(String friendlyTask) {
for (ServerTask serverTask : ServerTask.values()) {
if(serverTask.friendlyTask.equals(friendlyTask)) {
return serverTask;
}
}
return null;
}
The caveat to this approach is that the data won't be stored internally, and depending on how many enums you actually have and how many times you want to invoke this method, it would perform slightly worse than initializing with a map.
However, this approach is the most straightforward. If you find yourself in a position where you have several hundred enums (even more than 20 is a smell to me), consider what it is those enumerations represent and what one should do to break it out a bit more.
Create static reverse lookup map.
public enum ServerTask {
HOOK_BEFORE_ALL_TASKS("Execute"),
COPY_MASTER_AND_SNAPSHOT_TO_HISTORY("Copy master db"),
PROCESS_CHECKIN_QUEUE("Process Check-In Queue"),
...
FINAL_ITEM("Final item");
// For static data always prefer to use Guava's Immutable library
// http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableMap.html
static ImmutableMap< String, ServerTask > REVERSE_MAP;
static
{
ImmutableMap.Builder< String, ServerTask > reverseMapBuilder =
ImmutableMap.builder( );
// Build the reverse map by iterating all the values of your enum
for ( ServerTask cur : values() )
{
reverseMapBuilder.put( cur.taskName, cur );
}
REVERSE_MAP = reverseMapBuilder.build( );
}
// Now is the lookup method
public static ServerTask fromTaskName( String friendlyName )
{
// Will return ENUM if friendlyName matches what you stored
// with enum
return REVERSE_MAP.get( friendlyName );
}
}
If you have to get the enum from the String often, then creating a reverse map like Alexander suggests might be worth it.
If you only have to do it once or twice, looping over the values with a single if statement might be your best bet (like Nizil's comment insinuates)
for (ServerTask task : ServerTask.values())
{
//Check here if strings match
}
However there is a way to not iterate over the values at all. If you can ensure that the name of the enum instance and its String value are identical, then you can use:
ServerTask.valueOf("EXECUTE")
which will give you ServerTask.EXECUTE.
Refer this answer for more info.
Having said that, I would not recommend this approach unless you're OK with having instances have the same String representations as their identifiers and yours is a performance critical application which is most often not the case.
You could write a method like this:
static ServerTask getServerTask(String name)
{
switch(name)
{
case "Execute": return HOOK_BEFORE_ALL_TASKS;
case "Copy master db": return COPY_MASTER_AND_SNAPSHOT_TO_HISTORY;
case "Process Check-In Queue": return PROCESS_CHECKIN_QUEUE;
}
}
It's smaller, but not automatic like #Alexander_Pogrebnyak's solution. If the enum changes, you would have to update the switch.

How to check Type Ranges with Java development tools (JDT)?

I want to parse a String, which contains a number, using JDT to find out whether the contained number is inside the valid Range of one of the Primitive Types.
Let's say i got a float value like this as String "1.7976931348623157e350" and want to see whether it is still inside the allowed range for primitive type 'double'. (In this case it would not be inside the valid range, because the maximum exponent of double is 308).
I don't want to use the standard methods like : Double.parseDouble("1.7976931348623157e350"), because I'm afraid it might be too slow if I have a big amount of primitive types, which I want to check .
If you know the Eclipse development environment you will know that inside a normal java file, eclipse is able to tell whether a variable is out of range or not, by underlining it red, in the the case of 'out of range'. So basically i want to use this functionality. But as you can guess - it's easier said then done!
I have started experimenting with the ASTParser from this library: org.eclipse.jdt.core.dom
But I must admit I was not very successful here.
First i tried calling some of those vistor methods using methods like:
resolveBinding() , but they always only returned me "Null".
I have found some interesting class called ASTSyntaxErrorPropagator , but i'm not sure how this is used correctly. It seems to propagate parsing problems or something like that and gets it's information delivered by some thing class called CodeSnippetParsingUtil I assume. Anyways, these are only speculations.
Does anyone know how to use this ASTParser correctly?
I would be really thankful for some advice.
Here is some basic code-snipped which I tried to debug:
public class DatatypesParser {
public static void main(String[] args) {
ASTParser parser = ASTParser.newParser(AST.JLS4);
Map options = JavaCore.getOptions();
JavaCore.setComplianceOptions(JavaCore.VERSION_1_7, options);
String statement = new String("int i = " + Long.MAX_VALUE + ";");
parser.setSource(statement.toCharArray());
parser.setKind(ASTParser.K_STATEMENTS);
parser.setResolveBindings(true);
parser.setBindingsRecovery(true);
ASTNode ast = parser.createAST(null);
ast.accept(new ASTVisitor() {
#Override
public boolean visit(VariableDeclarationStatement node) {
CodeSnippetParsingUtil util = new CodeSnippetParsingUtil();
return true;
}
});
}
I don't want to use the standard methods like :
Double.parseDouble("1.7976931348623157e350"), because i'm afraid it
might be too slow if i have a big amount of primitive types, which i
want to check .
Under the hood JDT is actually using the standard methods of Double to parse the value, and quite a bit more - so you should always use the standard methods if performance is a concern.
Here is how the double gets parsed by JDT.
From org.eclipse.jdt.internal.compiler.ast.DoubleLiteral:
public void computeConstant() {
Double computedValue;
[...]
try {
computedValue = Double.valueOf(String.valueOf(this.source));
} catch (NumberFormatException e) {
[...]
return;
}
final double doubleValue = computedValue.doubleValue();
if (doubleValue > Double.MAX_VALUE) {
// error: the number is too large to represent
return;
}
[...]
}

How do I assert equality on two classes without an equals method?

Say I have a class with no equals() method, to which do not have the source. I want to assert equality on two instances of that class.
I can do multiple asserts:
assertEquals(obj1.getFieldA(), obj2.getFieldA());
assertEquals(obj1.getFieldB(), obj2.getFieldB());
assertEquals(obj1.getFieldC(), obj2.getFieldC());
...
I don't like this solution because I don't get the full equality picture if an early assert fails.
I can manually compare on my own and track the result:
String errorStr = "";
if(!obj1.getFieldA().equals(obj2.getFieldA())) {
errorStr += "expected: " + obj1.getFieldA() + ", actual: " + obj2.getFieldA() + "\n";
}
if(!obj1.getFieldB().equals(obj2.getFieldB())) {
errorStr += "expected: " + obj1.getFieldB() + ", actual: " + obj2.getFieldB() + "\n";
}
...
assertEquals("", errorStr);
This gives me the full equality picture, but is clunky (and I haven't even accounted for possible null problems). A third option is to use Comparator, but compareTo() will not tell me which fields failed equality.
Is there a better practice to get what I want from the object, without subclassing and overridding equals (ugh)?
There is many correct answers here, but I would like to add my version too. This is based on Assertj.
import static org.assertj.core.api.Assertions.assertThat;
public class TestClass {
public void test() {
// do the actual test
assertThat(actualObject)
.isEqualToComparingFieldByFieldRecursively(expectedObject);
}
}
UPDATE: In assertj v3.13.2 this method is deprecated as pointed out by Woodz in comment. Current recommendation is
public class TestClass {
public void test() {
// do the actual test
assertThat(actualObject)
.usingRecursiveComparison()
.isEqualTo(expectedObject);
}
}
Mockito offers a reflection-matcher:
For latest version of Mockito use:
Assert.assertTrue(new ReflectionEquals(expected, excludeFields).matches(actual));
For older versions use:
Assert.assertThat(actual, new ReflectionEquals(expected, excludeFields));
I generally implement this usecase using org.apache.commons.lang3.builder.EqualsBuilder
Assert.assertTrue(EqualsBuilder.reflectionEquals(expected,actual));
I know it's a bit old, but I hope it helps.
I run into the same problem that you, so, after investigation, I found few similar questions than this one, and, after finding the solution, I'm answering the same in those, since I thought it could to help others.
The most voted answer (not the one picked by the author) of this similar question, is the most suitable solution for you.
Basically, it consist on using the library called Unitils.
This is the use:
User user1 = new User(1, "John", "Doe");
User user2 = new User(1, "John", "Doe");
assertReflectionEquals(user1, user2);
Which will pass even if the class User doesn't implement equals(). You can see more examples and a really cool assert called assertLenientEquals in their tutorial.
If you're using hamcrest for your asserts (assertThat) and don't want to pull in additional test libs, then you can use SamePropertyValuesAs.samePropertyValuesAs to assert items that don't have an overridden equals method.
The upside is that you don't have to pull in yet another test framework and it'll give a useful error when the assert fails (expected: field=<value> but was field=<something else>) instead of expected: true but was false if you use something like EqualsBuilder.reflectionEquals().
The downside is that it is a shallow compare and there's no option for excluding fields (like there is in EqualsBuilder), so you'll have to work around nested objects (e.g. remove them and compare them independently).
Best Case:
import static org.hamcrest.beans.SamePropertyValuesAs.samePropertyValuesAs;
...
assertThat(actual, is(samePropertyValuesAs(expected)));
Ugly Case:
import static org.hamcrest.beans.SamePropertyValuesAs.samePropertyValuesAs;
...
SomeClass expected = buildExpected();
SomeClass actual = sut.doSomething();
assertThat(actual.getSubObject(), is(samePropertyValuesAs(expected.getSubObject())));
expected.setSubObject(null);
actual.setSubObject(null);
assertThat(actual, is(samePropertyValuesAs(expected)));
So, pick your poison. Additional framework (e.g. Unitils), unhelpful error (e.g. EqualsBuilder), or shallow compare (hamcrest).
You can use Apache commons lang ReflectionToStringBuilder
You can either specify the attributes you want to test one by one, or better, exclude those you don't want:
String s = new ReflectionToStringBuilder(o, ToStringStyle.SHORT_PREFIX_STYLE)
.setExcludeFieldNames(new String[] { "foo", "bar" }).toString()
You then compare the two strings as normal. For the point about reflection being slow, I assume this is only for testing, so shouldn't be so important.
Since this question is old, I will suggest another modern approach using JUnit 5.
I don't like this solution because I don't get the full equality picture if an early assert fails.
With JUnit 5, there is a method called Assertions.assertAll() which will allow you to group all assertions in your test together and it will execute each one and output any failed assertions at the end. This means that any assertions that fail first will not stop the execution of latter assertions.
assertAll("Test obj1 with obj2 equality",
() -> assertEquals(obj1.getFieldA(), obj2.getFieldA()),
() -> assertEquals(obj1.getFieldB(), obj2.getFieldB()),
() -> assertEquals(obj1.getFieldC(), obj2.getFieldC()));
The library Hamcrest 1.3 Utility Matchers has a special matcher that uses reflection instead of equals.
assertThat(obj1, reflectEquals(obj2));
Some of the reflection compare methods are shallow
Another option is to convert the object to a json and compare the strings.
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public static String getJsonString(Object obj) {
try {
ObjectMapper objectMapper = new ObjectMapper();
return bjectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
} catch (JsonProcessingException e) {
LOGGER.error("Error parsing log entry", e);
return null;
}
}
...
assertEquals(getJsonString(MyexpectedObject), getJsonString(MyActualObject))
AssertJ assertions can be used to compare the values without #equals method properly overridden, e.g.:
import static org.assertj.core.api.Assertions.assertThat;
// ...
assertThat(actual)
.usingRecursiveComparison()
.isEqualTo(expected);
Using Shazamcrest, you can do:
assertThat(obj1, sameBeanAs(obj2));
Compare field-by-field:
assertNotNull("Object 1 is null", obj1);
assertNotNull("Object 2 is null", obj2);
assertEquals("Field A differs", obj1.getFieldA(), obj2.getFieldA());
assertEquals("Field B differs", obj1.getFieldB(), obj2.getFieldB());
...
assertEquals("Objects are not equal.", obj1, obj2);
You can use reflection to "automate" the full equality testing. you can implement the equality "tracking" code you wrote for a single field, then use reflection to run that test on all fields in the object.
In case you just need flat fields comparison you can use AssertJ
Assertions.assertThat(actual)).isEqualToComparingFieldByField(expected);
This is a generic compare method , that compares two objects of a same class for its values of it fields(keep in mind those are accessible by get method)
public static <T> void compare(T a, T b) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
AssertionError error = null;
Class A = a.getClass();
Class B = a.getClass();
for (Method mA : A.getDeclaredMethods()) {
if (mA.getName().startsWith("get")) {
Method mB = B.getMethod(mA.getName(),null );
try {
Assert.assertEquals("Not Matched = ",mA.invoke(a),mB.invoke(b));
}catch (AssertionError e){
if(error==null){
error = new AssertionError(e);
}
else {
error.addSuppressed(e);
}
}
}
}
if(error!=null){
throw error ;
}
}
I stumbled on a very similar case.
I wanted to compare on a test that an object had the same attribute values as another one, but methods like is(), refEq(), etc wouldn't work for reasons like my object having a null value in its id attribute.
So this was the solution I found (well, a coworker found):
import static org.apache.commons.lang.builder.CompareToBuilder.reflectionCompare;
assertThat(reflectionCompare(expectedObject, actualObject, new String[]{"fields","to","be","excluded"}), is(0));
If the value obtained from reflectionCompare is 0, it means they are equal. If it is -1 or 1, they differ on some attribute.
In common case with AssertJ you can create custom comparator strategy:
assertThat(frodo).usingComparator(raceComparator).isEqualTo(sam)
assertThat(fellowshipOfTheRing).usingElementComparator(raceComparator).contains(sauron);
Using a custom comparison strategy in assertions
AssertJ examples
I had the exact same conundrum when unit testing an Android app, and the easiest solution I came up with was simply to use Gson to convert my actual and expected value objects into json and compare them as strings.
String actual = new Gson().toJson( myObj.getValues() );
String expected = new Gson().toJson( new MyValues(true,1) );
assertEquals(expected, actual);
The advantages of this over manually comparing field-by-field is that you compare all your fields, so even if you later on add a new field to your class it will get automatically tested, as compared to if you were using a bunch of assertEquals() on all the fields, which would then need to be updated if you add more fields to your class.
jUnit also displays the strings for you so you can directly see where they differ. Not sure how reliable the field ordering by Gson is though, that could be a potential problem.
I tried all the answers and nothing really worked for me.
So I've created my own method that compares simple java objects without going deep into nested structures...
Method returns null if all fields match or string containing mismatch details.
Only properties that have a getter method are compared.
How to use
assertNull(TestUtils.diff(obj1,obj2,ignore_field1, ignore_field2));
Sample output if there is a mismatch
Output shows property names and respective values of compared objects
alert_id(1:2), city(Moscow:London)
Code (Java 8 and above):
public static String diff(Object x1, Object x2, String ... ignored) throws Exception{
final StringBuilder response = new StringBuilder();
for (Method m:Arrays.stream(x1.getClass().getMethods()).filter(m->m.getName().startsWith("get")
&& m.getParameterCount()==0).collect(toList())){
final String field = m.getName().substring(3).toLowerCase();
if (Arrays.stream(ignored).map(x->x.toLowerCase()).noneMatch(ignoredField->ignoredField.equals(field))){
Object v1 = m.invoke(x1);
Object v2 = m.invoke(x2);
if ( (v1!=null && !v1.equals(v2)) || (v2!=null && !v2.equals(v1))){
response.append(field).append("(").append(v1).append(":").append(v2).append(")").append(", ");
}
}
}
return response.length()==0?null:response.substring(0,response.length()-2);
}
For Unit testing I just serialize the object to a JSON string and compare it.
For example with Gson:
import com.google.gson.GsonBuilder
import junit.framework.TestCase.assertEquals
class AssertEqualContent {
companion object {
val gson = GsonBuilder().create()
fun assertEqualContent(message: String?, expected: Any?, actual: Any?) {
assertEquals(message, gson.toJson(expected), gson.toJson(actual))
}
}
}
As the expected and actual object is supposed to be of the same type the field order will be the same.
Pros:
You will get a nice string comparison highligting exactly where the difference is.
No extra libraries (provided that you have a JSON library already)
Cons:
Objects of different types might produce the same JSON (but if they do, you might consider why do you have different classes for the same data.... and how they could end up being compared in a testing method :-)
Can you put the comparision code you posted into some static utility method?
public static String findDifference(Type obj1, Type obj2) {
String difference = "";
if (obj1.getFieldA() == null && obj2.getFieldA() != null
|| !obj1.getFieldA().equals(obj2.getFieldA())) {
difference += "Difference at field A:" + "obj1 - "
+ obj1.getFieldA() + ", obj2 - " + obj2.getFieldA();
}
if (obj1.getFieldB() == null && obj2.getFieldB() != null
|| !obj1.getFieldB().equals(obj2.getFieldB())) {
difference += "Difference at field B:" + "obj1 - "
+ obj1.getFieldB() + ", obj2 - " + obj2.getFieldB();
// (...)
}
return difference;
}
Than you can use this method in JUnit like this:
assertEquals("Objects aren't equal", "", findDifferences(obj1, obj));
which isn't clunky and gives you full information about differences, if they exist (through not exactly in normal form of assertEqual but you get all the info so it should be good).
From your comments to other answers, I don't understand what you want.
Just for the sake of discussion, lets say that the the class did override the equals method.
So your UT will look something like:
SomeType expected = // bla
SomeType actual = // bli
Assert.assertEquals(expected, actual).
And you are done. Moreover, you can not get the "full equality picture" if the assertion fails.
From what I understand, you are saying that even if the type did override equals, you would not be interested in it, since you want to get the "full equality picture". So there is no point in extending and overriding equals either.
So you have to options: either compare property by property, using reflection or hard-coded checks, I would suggest the latter. Or: compare human readable representations of these objects.
For example, you can create a helper class that serializes the type you wish tocompare to an XML document and than compare the resulting XML! in this case, you can visually see what exactly is equal and what is not.
This approach will give you the opportunity to look at the full picture but it is also relatively cumbersome (and a little error prone at first).
You can override the equals method of the class like:
#Override
public int hashCode() {
int hash = 0;
hash += (app != null ? app.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
HubRule other = (HubRule) object;
if (this.app.equals(other.app)) {
boolean operatorHubList = false;
if (other.operator != null ? this.operator != null ? this.operator
.equals(other.operator) : false : true) {
operatorHubList = true;
}
if (operatorHubList) {
return true;
} else {
return false;
}
} else {
return false;
}
}
Well, if you want to compare two object from a class you must implement in some way the equals and the hash code method

Using reserved words in an enum / switch statement, best workaround?

I am writing a flat file parser that reads token/value pairs using a Scanner. The files being read contain the token "class". The token is later used in a switch statement, and uses the (pre Java 7) valueOf(token) Java idiom to produce an enum value. (I am using Java6 for compatibility with GWT.) As a workaround, I am using uppercase values in the enum, and valueOf(token.toUpperCase()).
public enum ParseTags {
CODE, CLASS, INSTRUCTOR, HOURS;
}
// . . .
token = scanner.next();
value = scanner.next();
switch (ParseTags.valueOf(token.toUpperCase())) {
case CODE:
entry.setCode(value);
break;
case CLASS:
entry.setClass(value);
break;
Because this is being compiled into javascript, I want to avoid the extra "toUpperCase()" operation on each iteration; not sure what performance will be on target platform. Is there a more graceful way to represent reserved words in an enumeration? This would be handled well by Java7's switch on String, but again, I am confined to Java6sdk.
What you're doing right now is the preferred way to do it. I would be extraordinarily shocked if the toUpperCase were a bottleneck.
That said, I might consider something like
enum ParseTags {
CODE {
public void set(Entry entry, String value) {
entry.setCode(value);
}
},
...;
public abstract void set(Entry entry, String value);
}
so you can do
ParseTags.valueOf(token.toUpperCase()).set(entry, value);

Passing parameter to class property in Java

I have this property in a visual basic class. NET 2008, the property in addition to the get and set has a parameter called "pParam. "
Public Property UpdateField(ByVal pParam As String) As String
Get
Return Me.idField
End Get
Set(ByVal value As String)
Me.idField = value
If pParam = "NEW" Then
// some code here
End If
End Set
End Property
which is the equivalent of this in java code?
to use I do the following:
oClass.UpdateField("NEW") = 1850
I have this code in java
public void setUpdateField(String idField) {
this.idField = idField;
}
public String getUpdateField() {
return idField;
}
but I need to put the parameter "pParam"
Thanks in advance.
What you've got in the .NET code is an indexer in C# terms. There's no equivalent in Java - you'll just need to take two parameters:
public void setUpdateField(String idField, String pParam) {
...
}
Frankly I think it's a little odd that the "getter" in .NET doesn't seem to use the index...

Categories