i define a enum like below:
public enum EventType {
UPDATE(0), ADD(1), REMOVE(2), RESPONSE(3);
private Integer id;
public Integer id() {
return this.id();
}
/**
* constructor method
*/
EventType(Integer id) {
this.id = id;
}
public static EventType getInstance(Integer id) {
switch (id) {
case 0:
return UPDATE;
case 1:
return ADD;
case 2:
return REMOVE;
case 3:
return RESPONSE;
default:
return null;
}
}
}
I want to create a enum instance by callback getInstance method, the JNI code like below:
jclass eventType_cls = (*env)->FindClass(env,"com/example/hellojni/EventType");
jmethodID midInstance = (*env)->GetStaticMethodID(env,eventType_cls,"getInstance","(I)[Lcom/example/hellojni/EventType;");
it pass the compiler, but when run to the JNI GetStaticMethodID method, the platform throws a error like below:
java.lang.NoSuchMethodError: no static method with name='getInstance'
signature='(I)Lcom/example/hellojni/EventType;'
in class Lcom/example/hellojni/EventType;
I don't know what's different enum with other class, do you have any idea?
The signature that you use in JNI for the method is looking for a method that looks like this:
public static EventType[] getInstance(int id) {
}
So the return type of the signature is definitely wrong. It should not have the [ there.
Now you have two possibilities either change the input type to int on the Java side or you change the type signature to (Ljava/lang/Integer;)Lcom/example/hellojni/EventType;.
Now you will realize that the second alternative is not very easy to handle since to access the value of the Integer you would have to use JNI methods and all the other fuzz.
You should also rethink why you would ever want to use the Integer wrapper instead of the primitive int in you Java code. There is simply no reason for it.
Rewrite your enum to something look like this:
public enum EventType {
UPDATE(0), ADD(1), REMOVE(2), RESPONSE(3);
private int id;
public int id() {
return this.id();
}
/**
* constructor method
*/
EventType(int id) {
this.id = id;
}
public static EventType getInstance(int id) {
switch (id) {
case 0:
return UPDATE;
case 1:
return ADD;
case 2:
return REMOVE;
case 3:
return RESPONSE;
default:
return null;
}
}
}
And change the JNI method lookup to this:
jmethodID midInstance = (*env)->GetStaticMethodID(env,eventType_cls,"getInstance","(I)Lcom/example/hellojni/EventType;");
Related
I have got an Enum with different values and want to switch a string variable. Now I hit a wall trying to convert the Enum values to Strings, that I can use as case constant.
My best try was to convert the Enum to a String array, but the switch doesn't seem to accept array values as a case constant. (IntelliJ says: "constant expression required")
Enum myEnum = {FOO, BAR}
String input = "foo"
final String[] constant = Arrays.stream(myEnum.values()).map(Enum::name).toArray(String[]::new);
//converts Enum to String[]; made it final, so it is "constant"
switch (input) {
case constant[0]:
System.out.println("foo");
break;
case constant[1]:
System.out.println("bar");
break;
}
Is there an elegant way to make this switch depend on the Enum?
You shouldn't convert it because it isn't needed. Also, your code won't even compile because case is a reserved keyword in Java.
You should take a look at the valueOf method of an Enum.
Your code can look like that:
public enum MyEnum {FOO, BAR}
//method
String input = "foo";
MyEnum niceFound = MyEnum.valueOf(input.toUpperCase());
That will return FOO but can throw an IllegalArgumentException when the given value isn't present as type.
You can do this :
public enum MyEnum {
FOO("foo"),
BAR("bar");
private String value;
public String getValue() {
return value;
}
public static MyEnum getState(String value) {
switch (value) {
case "foo":
return FOO;
case "bar":
return BAR;
}
return null;
}
private MyEnum(String value) {
this.value = value;
}
}
Now, in your class, you can :
MyEnum myEnum = getState("foo"); // returns MyEnum.FOO
Also make sure you handle the case when getState() returns null
A solution with Java 8+ streams would be to create a method inside your enum :
public static Optional<MyEnum> getByValue(final String value) {
return Arrays.stream(MyEnum.values())
.filter(myEnum -> myEnum.value.equals(value))
.findFirst();
}
This returns optional in case there is no enum value for your String parameter. But you can change it according to your needs.
Use MyEnum.valueOf(value.toUpperCase())
public enum MyEnum {
FOO, BAR;
}
public static void process(String value) {
try {
switch (MyEnum.valueOf(value.toUpperCase())) {
case FOO :
System.out.println("FOO");
break;
case BAR :
System.out.println("BAR");
break;
default :
break;
}
}
catch (IllegalArgumentException e) {
// TODO: handle exception
}
public static void main(String[] a){
process("foo");
}
I have the following:
public class Stat {
public enum HitType {
MOBILE1(0), MOBILE2(1), DESKTOP(2);
public final int value;
public int value() { return value; }
HitType(int val) {
value = val;
}
public static HitType parseInt(int i) {
switch (i) {
case 0: return MOBILE1;
case 1: return MOBILE2;
case 2: return DESKTOP;
default: return null;
}
}
}
public HitType hitType;
public long sourceId;
public Stat(... int hitType, BigInteger sourceId) {
this.hitType = HitType.parseInt(hitType);
this.sourceId = sourceId.longValueExact();
#Mapper
public interface StatMapper {
#Select("select * from stats where id = #{id}")
#Results(value = {
#Result(property = "hitType", column = "hit_type"),
...
})
public Stat findById(#Param("id") long id);
Stat s = statMapper.findById(1);
response.getOutputStream().print(s.toString());
It still gives this error:
Resolved exception caused by Handler execution: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'hit_type' from result set.
Cause: java.lang.IllegalArgumentException: No enum constant com.company.app.model.Stat.HitType.2
I tried http://stackoverflow.com/questions/5878952/ddg#5878986 and read Convert integer value to matching Java Enum.
If I change the constructor signature to
public Stat(..., int hitType, long sourceId) {
this.sourceId = sourceId;
Then it gives the error
nested exception is org.apache.ibatis.executor.ExecutorException: No constructor found in com.company.app.model.Stat matching [java.math.BigInteger, java.lang.String, java.sql.Timestamp, java.lang.Integer, java.math.BigInteger]
So it seems in the first case it may be setting properties directly, while in the 2nd case, it is using the constructor.
I tried putting HitType hitType in the constructor signature, but it still gives me the No constructor found... error.
MyBatis 3.4.5, MyBatis-Spring 1.3.1, Spring-Boot 1.5.13
I added the getter & setter for that type
public HitType getHitType() {
return hitType;
}
public void setHitType(int hitType) {
this.hitType = HitType.parseInt(hitType);
}
And then it started working. Which is weird because it was complaining about the constructor signature. If it is using the constructor, why would it need the getters and setters?
Am trying to use Enum as Constants for readability as below .
Public enum x { test1 , test2 , test3 }
I want to pass this enum into a method and use it as a int value as shown
private void (int type)
{
switch(int)
{
case enum.X:
// do somthing
break;
}
} ;
Can we use enum here as its more clearer than using a int value .( like switch 1 etc) . Is it possible to use this way.?
Yes, you should be able to use an enum in a switch statement in Java:
public enum SomeEnum { FOO, BAR, BAZ };
// in a class...
private void something(SomeEnum s) {
switch (s) {
case FOO:
// do something
break;
case BAR:
// do something else
break;
}
}
Not sure I understand how int values tie into this, but you can have fields/methods on an enum like in a normal Java class, and can use these to hold int (or any other type) values as on any other POJO.
Here's an example in which we declare a constructor for an enum class, so that you can pass in values for internal variables at the time each instance of the enum is constructed. To help you follow what's going on: First we declare the items in the enum - each declaration invokes the constructor, so we can pass in instance variables here. Then the code for the enum class follows, as with a normal Java class.
public enum AnotherEnum {
ONE(1, "un"), TWO(2, "deux"), THREE(3, "trois"), FIFTY_SEVEN(57, "cinquante-sept");
private final int someInt;
private final String french;
private AnotherEnum(int i, String s) {
this.someInt = i;
this.french = s;
}
public int getSomeInt() {
return this.someInt;
}
public String getFrench() {
return this.french;
}
}
So for example, System.out.println(AnotherEnum.TWO.getSomeInt()) would print 2, and System.out.println(AnotherEnum.FIFTY_SEVEN.getFrench()) would print cinquante-sept.
No, you cannot say:
case Enumerator.ordinal():
But you could say:
switch(EnumObject.values()[intVar]) {
case Enumerator1:
...
}
Another way you can do this by doing a little more work with you enum class.
public enum Foo {
X (1),
Y (2);
private int value;
Foo (int value)
{
this.value = value;
}
}
Now all you need to do is:
switch (int)
{
case Foo.X: doSomething ();break;
case Foo.Y: doSomething ();break;
}
in an interface, I store constants in this way (I'd like to know what you think of this practice). This is just a dummy example.
interface HttpConstants {
/** 2XX: generally "OK" */
public static final int HTTP_OK = 200;
public static final int HTTP_CREATED = 201;
public static final int HTTP_ACCEPTED = 202;
public static final int HTTP_NOT_AUTHORITATIVE = 203;
public static final int HTTP_NO_CONTENT = 204;
public static final int HTTP_RESET = 205;
public static final int HTTP_PARTIAL = 206;
...
}
Is there a way I can iterate over all constants declared in this interface ?
Using reflection:
Field[] interfaceFields=HttpConstants.class.getFields();
for(Field f:interfaceFields) {
//do something
}
But anyway, if you can redesign your class, I would recomend you to handle a static enum constants construction. So, suposing your class will contain always an int value for every constant:
enum HttpConstants {
HTTP_OK(200), HTTP_CREATED(201), HTTP_ACCEPTED(202),
HTTP_NOT_AUTHORITATIVE(203),HTTP_NO_CONTENT(204),
HTTP_RESET(205), HTTP_PARTIAL(206) /* ... */;
private int value;
HttpConstants(int aValue) {
value=aValue;
}
public int getValue() {
return value;
}
}
Then, to loop on it:
for(HttpConstants val: HttpConstants.values()) {
int value=val.getValue();
//...
}
Thus, avoiding the access to the reflection API.
I would create these constants as an enumeration. Enums in Java can have their own fields and methods, which very convenient for your case. So I would do this the following way:
enum HttpConstant {
HTTP_OK(200),
HTTP_CREATED(201),
HTTP_ACCEPTED(202),
HTTP_NOT_AUTHORITATIVE(203),
HTTP_NO_CONTENT(204),
HTTP_RESET(205),
HTTP_PARTIAL(206);
private final int id;
HttpConstant(int id) {
this.id = id;
}
int getId() {
return id;
}
}
Now the iteration is easy:
for (HttpConstant constant : HttpConstant.values()) {
//Do something with the constant
}
This way it is also easy to add associate some new values with the constants, you just have to add new fields.
Right now you may use reflection:
Field[] interfaceFields = HttpConstants.class.getFields();
for (Field field : interfaceFields) {
int constant = field.getInt(null);
//Do something with the field
}
However, it is better to use the approach with enums because with reflection coding errors result in runtime exceptions instead of compile-time errors.
for(Field f : HttpConstants.class.getFields()){
int constant = f.getInt(null);
}
public enum HttpConstant {
/** 2XX: generally "OK" */
HTTP_OK(200).
HTTP_CREATED(201),
HTTP_ACCEPTED(202),
HTTP_NOT_AUTHORITATIVE(203),
HTTP_NO_CONTENT(204),
HTTP_RESET(205),
HTTP_PARTIAL(206);
private int code;
private HttpConstant(int code) {
this.code = code;
}
public int getCode() {
return code;
}
}
with HttpConstant.values().
Well usually when i have something like that i make a Map in the interface that has the keys - constant names with values constant - values.
And that's how i can iterate over them.
I'd like to know what you think of this practice
Consider using an enum instead of an interface with constants.
enum HttpResultCode {
HTTP_OK(200),
HTTP_CREATED(201),
HTTP_ACCEPTED(202),
HTTP_NOT_AUTHORITATIVE(203),
HTTP_NO_CONTENT(204),
HTTP_RESET(205),
HTTP_PARTIAL(206);
private final int code;
private HttpResultCode(int code) {
this.code = code;
}
public int getCode(int code) {
return code;
}
public static HttpResultCode forCode(int code) {
for (HttpResultCode e : HttpResultCode.values()) {
if (e.code == code) {
return e;
}
}
throw new IllegalArgumentException("Invalid code: " + code);
}
}
two class:
public class BaseDo<K> {
protected K id;
public K getId() {
return id;
}
public void setId(K id) {
this.id = id;
}
}
public class BeanDo extends BaseDo<Integer> {
private String beanName;
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
}
I want use reflect to implment like this:
BeanDo beanDo = new BeanDo();
beanDo.setId("string here");
Integer type reference String type value.
Generics in Java are not used at runtime, so as far as the java runtime is concerned you're ID field is of type Object and so can be set to any value regardless of the generics. That said, doing so is a bad idea since anything assuming the generic contract will fail.
You can set the field by reflection as follows:
BeanDo beanDo = new BeanDo();
Method method = BeanDo.getClass().getMethod("setId", Object.class);
method.invoke(beanDo, "SomeRandomString");
That said, doing this is an extreamly bad idea because any code compile against BeanDo will assume that the id is an integer not a String. So any code like beanDo.getId() will fail with a class cast exception because it's not actually an integer.
Like the other posters, I'm somewhat in the dark about what you're trying to achieve.
Something like this?
public class BaseDo<K> {
protected K id;
public K getId() {
return id;
}
public void setId(K id) {
this.id = id;
}
}
public class BeanDo extends BaseDo<Integer> {
private String beanName;
public void setId(String id) {
setId(Integer.parseInt(id));
}
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
}
Now you can use something like this:
BeanDo beanDo = new BeanDo();
beanDo.setId("2");
What about this:
BeanDo beando = new BeanDo();
beando.setId("string there".hashCode());
I don't quite get what you mean with "I want to use reflect to implement this" though.
I guess you want something like this:
BeanDo doer = ... // get it from somewhere
String id = ... // get it from somewhere else too.
// and you want to set id to the doer bean.
reflectionMagicSetId( doer, id );
And have the method like:
private void reflectionMagicSetId( BandDo doer, String id ) {
/// do some magic here?
}
If that's what you want, what I give you works perfectly.
private void reflectionMagicSetId( BandDo doer, String id ) {
doer.setId( id == null ? 0 : id.hashCode() );
}
If you wann use integer then parse the string to integer as it will contain the integer and use that integer in the calling function argument
It seems like a subclass about the only way to be able to set a string, but still guarantee that anyone who's already calling getId() gets the Integer they expect. Something like this:
public class StringBeanDo extends BeanDo {
private String stringId;
public String getStringId()
{
return stringId;
}
public void setId( Integer val )
{
super.setId( val );
stringId = Integer.toString( val );
}
public void setId( String str )
{
stringId = str;
super.setId( convertStringToInteger( str )); // Do this however you like.
}
}
The implementation of convertStringToInteger would be up to you (it'll depend on what this ID is being used for). The key here is that you're maintaining TWO IDs, and keeping them in sync, so that older code can still limp along to some extent.