ObjectInputStream.GetField and ObjectOutputStream.PutField - java

Does anybody maybe know how ObjectInputStream.GetField and ObjectOutputStream.PutField are used. my program need to look for specific objects at specific times and the above classes would really help me get it right.

ObjectOutputStream.PutField:
private class PutFieldImpl extends PutField {
/** class descriptor describing serializable fields */
private final ObjectStreamClass desc;
/** primitive field values */
private final byte[] primVals;
/** object field values */
private final Object[] objVals;
/**
* Creates PutFieldImpl object for writing fields defined in given
* class descriptor.
*/
PutFieldImpl(ObjectStreamClass desc) {
this.desc = desc;
primVals = new byte[desc.getPrimDataSize()];
objVals = new Object[desc.getNumObjFields()];
}
public void put(String name, boolean val) {
Bits.putBoolean(primVals, getFieldOffset(name, Boolean.TYPE), val);
}
public void put(String name, byte val) {
primVals[getFieldOffset(name, Byte.TYPE)] = val;
}
public void put(String name, char val) {
Bits.putChar(primVals, getFieldOffset(name, Character.TYPE), val);
}
public void put(String name, short val) {
Bits.putShort(primVals, getFieldOffset(name, Short.TYPE), val);
}
public void put(String name, int val) {
Bits.putInt(primVals, getFieldOffset(name, Integer.TYPE), val);
}
public void put(String name, float val) {
Bits.putFloat(primVals, getFieldOffset(name, Float.TYPE), val);
}
public void put(String name, long val) {
Bits.putLong(primVals, getFieldOffset(name, Long.TYPE), val);
}
public void put(String name, double val) {
Bits.putDouble(primVals, getFieldOffset(name, Double.TYPE), val);
}
public void put(String name, Object val) {
objVals[getFieldOffset(name, Object.class)] = val;
}
// deprecated in ObjectOutputStream.PutField
public void write(ObjectOutput out) throws IOException {
/*
* Applications should *not* use this method to write PutField
* data, as it will lead to stream corruption if the PutField
* object writes any primitive data (since block data mode is not
* unset/set properly, as is done in OOS.writeFields()). This
* broken implementation is being retained solely for behavioral
* compatibility, in order to support applications which use
* OOS.PutField.write() for writing only non-primitive data.
*
* Serialization of unshared objects is not implemented here since
* it is not necessary for backwards compatibility; also, unshared
* semantics may not be supported by the given ObjectOutput
* instance. Applications which write unshared objects using the
* PutField API must use OOS.writeFields().
*/
if (ObjectOutputStream.this != out) {
throw new IllegalArgumentException("wrong stream");
}
out.write(primVals, 0, primVals.length);
ObjectStreamField[] fields = desc.getFields(false);
int numPrimFields = fields.length - objVals.length;
// REMIND: warn if numPrimFields > 0?
for (int i = 0; i < objVals.length; i++) {
if (fields[numPrimFields + i].isUnshared()) {
throw new IOException("cannot write unshared object");
}
out.writeObject(objVals[i]);
}
}
/**
* Writes buffered primitive data and object fields to stream.
*/
void writeFields() throws IOException {
bout.write(primVals, 0, primVals.length, false);
ObjectStreamField[] fields = desc.getFields(false);
int numPrimFields = fields.length - objVals.length;
for (int i = 0; i < objVals.length; i++) {
if (extendedDebugInfo) {
debugInfoStack.push(
"field (class \"" + desc.getName() + "\", name: \"" +
fields[numPrimFields + i].getName() + "\", type: \"" +
fields[numPrimFields + i].getType() + "\")");
}
try {
writeObject0(objVals[i],
fields[numPrimFields + i].isUnshared());
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
}
/**
* Returns offset of field with given name and type. A specified type
* of null matches all types, Object.class matches all non-primitive
* types, and any other non-null type matches assignable types only.
* Throws IllegalArgumentException if no matching field found.
*/
private int getFieldOffset(String name, Class type) {
ObjectStreamField field = desc.getField(name, type);
if (field == null) {
throw new IllegalArgumentException("no such field " + name +
" with type " + type);
}
return field.getOffset();
}
}
ObjectInputStream.GetField:
private class GetFieldImpl extends GetField {
/** class descriptor describing serializable fields */
private final ObjectStreamClass desc;
/** primitive field values */
private final byte[] primVals;
/** object field values */
private final Object[] objVals;
/** object field value handles */
private final int[] objHandles;
/**
* Creates GetFieldImpl object for reading fields defined in given
* class descriptor.
*/
GetFieldImpl(ObjectStreamClass desc) {
this.desc = desc;
primVals = new byte[desc.getPrimDataSize()];
objVals = new Object[desc.getNumObjFields()];
objHandles = new int[objVals.length];
}
public ObjectStreamClass getObjectStreamClass() {
return desc;
}
public boolean defaulted(String name) throws IOException {
return (getFieldOffset(name, null) < 0);
}
public boolean get(String name, boolean val) throws IOException {
int off = getFieldOffset(name, Boolean.TYPE);
return (off >= 0) ? Bits.getBoolean(primVals, off) : val;
}
public byte get(String name, byte val) throws IOException {
int off = getFieldOffset(name, Byte.TYPE);
return (off >= 0) ? primVals[off] : val;
}
public char get(String name, char val) throws IOException {
int off = getFieldOffset(name, Character.TYPE);
return (off >= 0) ? Bits.getChar(primVals, off) : val;
}
public short get(String name, short val) throws IOException {
int off = getFieldOffset(name, Short.TYPE);
return (off >= 0) ? Bits.getShort(primVals, off) : val;
}
public int get(String name, int val) throws IOException {
int off = getFieldOffset(name, Integer.TYPE);
return (off >= 0) ? Bits.getInt(primVals, off) : val;
}
public float get(String name, float val) throws IOException {
int off = getFieldOffset(name, Float.TYPE);
return (off >= 0) ? Bits.getFloat(primVals, off) : val;
}
public long get(String name, long val) throws IOException {
int off = getFieldOffset(name, Long.TYPE);
return (off >= 0) ? Bits.getLong(primVals, off) : val;
}
public double get(String name, double val) throws IOException {
int off = getFieldOffset(name, Double.TYPE);
return (off >= 0) ? Bits.getDouble(primVals, off) : val;
}
public Object get(String name, Object val) throws IOException {
int off = getFieldOffset(name, Object.class);
if (off >= 0) {
int objHandle = objHandles[off];
handles.markDependency(passHandle, objHandle);
return (handles.lookupException(objHandle) == null) ?
objVals[off] : null;
} else {
return val;
}
}
/**
* Reads primitive and object field values from stream.
*/
void readFields() throws IOException {
bin.readFully(primVals, 0, primVals.length, false);
int oldHandle = passHandle;
ObjectStreamField[] fields = desc.getFields(false);
int numPrimFields = fields.length - objVals.length;
for (int i = 0; i < objVals.length; i++) {
objVals[i] =
readObject0(fields[numPrimFields + i].isUnshared());
objHandles[i] = passHandle;
}
passHandle = oldHandle;
}
/**
* Returns offset of field with given name and type. A specified type
* of null matches all types, Object.class matches all non-primitive
* types, and any other non-null type matches assignable types only.
* If no matching field is found in the (incoming) class
* descriptor but a matching field is present in the associated local
* class descriptor, returns -1. Throws IllegalArgumentException if
* neither incoming nor local class descriptor contains a match.
*/
private int getFieldOffset(String name, Class type) {
ObjectStreamField field = desc.getField(name, type);
if (field != null) {
return field.getOffset();
} else if (desc.getLocalDesc().getField(name, type) != null) {
return -1;
} else {
throw new IllegalArgumentException("no such field " + name +
" with type " + type);
}
}
}
/e1
You get an instance of PutField by calling ObjectOutputStream#putFields and likewise you get an instance of GetField by calling ObjectInputStream#readFields.

Related

Unexpected exception expected <nameoftheclass> but was <java.lang.AssertionError>

i donĀ“t know how to pass this test. I tried every solution i thought of and didnt find a solution on the internet neither. Its my exam to school.
So, I have this class MojeException.java:
public class MojeException extends RuntimeException {
/**
* Creates a new instance of <code>NewException</code> without detail
* message.
*/
public MojeException() throws AssertionError{
}
/**
* Constructs an instance of <code>NewException</code> with the specified
* detail message.
*
* #param msg the detail message.
*/
public MojeException(String msg) throws AssertionError {
super(msg);
}
}
And i have this test:
#Test(expected = MojeException.class)
public void testKonstruktor11() {
Rozmer rozmer = new Rozmer(0, 0, 0);
fail() ;
}
The error i got is "Unexpected exception, expected but was<java.lang.AssertionError>"
The main class is this, however i dont know if its not irelevant:
public class Rozmer {
public static final double DIMENZE_MAX = 100;
public static final double DIMENZE_MIN = .1;
private static final double TO_CM = 100.00;
private final long delka;
private final long sirka;
private final long vyska;
public Rozmer(double delka, double sirka, double vyska){
this.delka = (long)(delka * TO_CM);
this.sirka = (long) (sirka * TO_CM);
this.vyska = (long) (vyska * TO_CM);
}
public double getDelka() {
return delka/TO_CM;
}
public double getSirka() {
return sirka/TO_CM;
}
public double getVyska() {
return vyska/TO_CM;
}
#Override
public String toString() {
return "Rozmer{" + "delka= " + delka/TO_CM + "0,sirka= " + sirka/TO_CM + "0,vyska= " + vyska/TO_CM + "0}";
}
#Override
public int hashCode() {
int hash = 7;
hash = 89 * hash + (int) (this.delka ^ (this.delka >>> 32));
hash = 89 * hash + (int) (this.sirka ^ (this.sirka >>> 32));
hash = 89 * hash + (int) (this.vyska ^ (this.vyska >>> 32));
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Rozmer other = (Rozmer) obj;
if (this.delka != other.delka) {
return false;
}
if (this.sirka != other.sirka) {
return false;
}
if (this.vyska != other.vyska) {
return false;
}
return true;
}
public static boolean kontrolaDimenze(double dimenze) {
return DIMENZE_MIN <= dimenze && dimenze<=DIMENZE_MAX;
}
Thanks for all your ideas and solutions :)
Basically, you are instructing JUnit that in your test you expect that a MojeException (which is a RuntimeException) will be eventually thrown, and that it's not done by fail(), which instead throws an AssertionException, so a total different one.
So, you have to throw that specific exception somewhere, otherwise your test will always fail.
The best point to do that is possibly in your constructor, because it's the only method you invoked in the test, so it looks like you are testing that specific constructor. Maybe after checking one of the input parameters, which doesn't match an expected value, you can throw your exception.
Here is just an example of how you can modify your Rozmer class constructor:
public Rozmer(double delka, double sirka, double vyska) throws MojeException {
if(delka == 0.0 || sirka == 0.0 || vyska == 0.0) {
throw new MojeException("Unsupported value for delka, sirka or vyska");
}
this.delka = (long)(delka * TO_CM);
this.sirka = (long) (sirka * TO_CM);
this.vyska = (long) (vyska * TO_CM);
}
Then remove the fail() from your test.

Java Implement an interface type method in implement interface

There is an interface called Range like
public interface Range {
public Range newRange(int from,int to);
public boolean isIn(int value);
public int min();
public int max();
public Range add(Range r);
}
In the implement interface, the Range newRange(1,5) is to set a range number from 1 to 5, and the method Range add(Range r.newRange(6,8)) adds the range from 1 to 5 plus 6 to 8 based on the method Range newRange(1,5). boolean isIn(int value) return if the value is in this range.int min() return the minimum value in the range. How can I implement the methods using class as a reference type? By passing an object? My newRange is
public Range newRange(int from,int to){
RangeImplem impIns = new RangeImplem();
impIns.from = from;
impIns.to = to;
return impIns;
}
I have no idea on this question and a little confusing on the class as reference type. Thanks.
I think your interface is incorrect.
You call it Range, but inside it can hold multiple ranges.
So for good solution add methods to the Range to get multiple ranges.
Or here some workarounds:
import java.util.HashSet;
import java.util.Set;
public class RangeImpl implements Range {
private class SimpleRange {
public SimpleRange(int from, int to) {
this.from = from;
this.to = to;
}
final int from;
final int to;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SimpleRange that = (SimpleRange) o;
if (from != that.from) return false;
return to == that.to;
}
#Override
public int hashCode() {
int result = from;
result = 31 * result + to;
return result;
}
}
private Set<SimpleRange> ranges=new HashSet<>();
#Override
public Range add(int from, int to) {
ranges.add(new SimpleRange(from, to));
return this;
}
#Override
public int min() {
return 0;
}
#Override
public int max() {
return 0;
}
#Override
public Range add(Range r) {
//1) first way If there is only 1 your implementation of Range.
//extract ranges from inside
if (ranges instanceof RangeImpl) {
RangeImpl ri= (RangeImpl) r;
ranges.addAll(ri.ranges);
}
return this;
}
// way2:
#Override
public boolean isIn(int value) {
for (Range externalRange : externalRanges) {
externalRange.isIn()
}
for (SimpleRange range : ranges) {
range isin
}
return false;
}
#Override
Set<Range> externalRanges=new HashSet<>();
//cache supplied ranges and use them in ither methods
public Range add(Range r) {
externalRanges.add(r);
return this;
}
}
Here is your answer:
package com.genpact.java.interf;
public interface Range {
/**
* Create a new Range object representing an integer interval starting from 'from' and 'to', both limits inclusive
*/
public Range newRange(int from,int to);
/**
* Return if 'value' is in the range defined by this object
*/
public boolean isIn(int value);
/**
* Return the minimum value in range
*/
public int min();
/**
* Return the maximum value in range
*/
public int max();
/**
* Add range 'r' to this range, and return 'this'.
* 'r' and this may denote disjoint ranges, for instance:
* r.newRange(1,5).add(r.newRange(8,10)) denotes a range
* including 1,2,3,4,5,8,9,10
*/
public Range add(Range r);
}
package com.genpact.java.impl;
import com.genpact.java.interf.Range;
public class RangeImplem implements Range {
private int from;
private int to;
public RangeImplem() {
// TODO Auto-generated constructor stub
}
public RangeImplem(int from, int to) {
this.from = from;
this.to = to;
}
#Override
public Range newRange(int from, int to) {
Range range=new RangeImplem(from, to);
return range;
}
#Override
public boolean isIn(int value) {
//Return if 'value' is in the range defined by this object
if(value >= this.from && value <= this.to){
return true;
}
return false;
}
#Override
public int min() {
return this.from;
}
#Override
public int max() {
return this.to;
}
#Override
public Range add(Range r) {
this.from = r.min();
this.to = r.min();
return newRange(this.from,this.to);
}
public static void main(String[] args) {
RangeImplem r=new RangeImplem();
System.out.println(r.newRange(1,5).isIn(3)); //=> returns true
System.out.println(r.newRange(1,5).isIn(6)); //=> returns false
System.out.println(r.newRange(1,5).add(r.newRange(8,10)).isIn(6)); //=> returns false
}
}

Java: make prefix tree remember last value that was not null

I have code for prefix tree (Trie) like this:
public class Trie<V> {
Entry<V> entry;
char key;
Map<Character, Trie<V>> childrens;
public Trie() {
this.childrens = new HashMap<Character, Trie<V>>(10);
entry = new Entry<V>();
}
/** non-public, used by _put() */
Trie(char key) {
this.childrens = new HashMap<Character, Trie<V>>(10);
this.key = key;
entry = new Entry<V>();
}
public void put(String key, V value) {
_put(new StringBuffer(key), new StringBuffer(""), value);
}
void _put(StringBuffer remainder, StringBuffer prefix, V value) {
if (remainder.length() > 0) {
char keyElement = remainder.charAt(0);
Trie<V> t = null;
try {
t = childrens.get(keyElement);
} catch (IndexOutOfBoundsException e) {
}
if (t == null) {
t = new Trie<V>(keyElement);
childrens.put(keyElement, t);
}
prefix.append(remainder.charAt(0));
t._put(remainder.deleteCharAt(0), prefix, value);
} else {
this.entry.value = value;
this.entry.prefix = prefix.toString();
}
}
/**
* Retrieves element from prefix table matching as a prefix to provided key.
* E.g. is key is "abcde" and prefix table has node "ab" then this call will
* return "ab"
*
* #param key
* a string which starts with prefix to be searched in the table
* (e.g. phone number)
* #return an Object assosiated with matching prefix (i.e if key is a phone
* number it may return a corresponding country name)
*/
public V get(String key) {
return _get(new StringBuffer(key), 0);
}
/**
* Returns true if key has matching prefix in the table
*/
public boolean hasPrefix(String key) {
return ((this.get(key) != null) ? true : false);
}
V _get(StringBuffer key, int level) {
if (key.length() > 0) {
Trie<V> t = childrens.get(key.charAt(0));
if (t != null) {
return t._get(key.deleteCharAt(0), ++level);
} else {
return (level > 0) ? entry.value : null;
}
} else {
return entry.value;
}
}
#Override
public String toString() {
return "Trie [entry=" + entry + ", key=" + key + ", childrens="
+ childrens + "]";
}
static public class Entry<V> {
String prefix;
V value;
public Entry() {
}
public Entry(String p, V v) {
prefix = p;
value = v;
}
public String prefix() {
return prefix;
}
public V value() {
return value;
}
#Override
public String toString() {
return "Entry [prefix=" + prefix + ", value=" + value + "]";
}
}
}
Insertion goes like this:
private static Trie<String> trie = new Trie<>();
trie.put("7", "Some country");
trie.put("77", "Some other country");
trie.put("745", "Entirely different place");
Searching will go like this:
String result = trie.get("746878788");
System.out.println(result);
This search will result null because there is no value for 74.
My question is: how can I modify _get method in Trie class so that it will remember last value that is not null. So when it ends up in 74, then it will remember that 7 had some value "Some country", so it will return that instead of null.
Any ideas how to solve this?
Any help is appreciated!
First of all, I modified the toString() method of the Trie to get some better debug information. The only important rows to achieve what you are asking are these in _get method:
V result = t._get(key.deleteCharAt(0), ++level);
return result == null ? entry.value : result;
The trie now prefers current entry's value, if subentry's value is null.
The whole code modified:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class Trie<V> {
Entry<V> entry;
char key;
Map<Character, Trie<V>> children;
public Trie() {
this.children = new HashMap<Character, Trie<V>>(10);
entry = new Entry<V>();
}
/** non-public, used by _put() */
Trie(char key) {
this.children = new HashMap<Character, Trie<V>>(10);
this.key = key;
entry = new Entry<V>();
}
public void put(String key, V value) {
_put(new StringBuffer(key), new StringBuffer(""), value);
}
void _put(StringBuffer remainder, StringBuffer prefix, V value) {
if (remainder.length() > 0) {
char keyElement = remainder.charAt(0);
Trie<V> t = null;
try {
t = children.get(keyElement);
} catch (IndexOutOfBoundsException e) {
}
if (t == null) {
t = new Trie<V>(keyElement);
children.put(keyElement, t);
}
prefix.append(remainder.charAt(0));
t._put(remainder.deleteCharAt(0), prefix, value);
} else {
this.entry.value = value;
this.entry.prefix = prefix.toString();
}
}
/**
* Retrieves element from prefix table matching as a prefix to provided key.
* E.g. is key is "abcde" and prefix table has node "ab" then this call will
* return "ab"
*
* #param key
* a string which starts with prefix to be searched in the table
* (e.g. phone number)
* #return an Object assosiated with matching prefix (i.e if key is a phone
* number it may return a corresponding country name)
*/
public V get(String key) {
return _get(new StringBuffer(key), 0);
}
/**
* Returns true if key has matching prefix in the table
*/
public boolean hasPrefix(String key) {
return ((this.get(key) != null) ? true : false);
}
V _get(StringBuffer key, int level) {
if (key.length() > 0) {
Trie<V> t = children.get(key.charAt(0));
if (t != null) {
V result = t._get(key.deleteCharAt(0), ++level);
return result == null ? entry.value : result;
} else {
return (level > 0) ? entry.value : null;
}
} else {
return entry.value;
}
}
#Override
public String toString() {
Iterator<Character> it = children.keySet().iterator();
StringBuffer childs = new StringBuffer();
while (it.hasNext()) {
Character key = it.next();
childs.append(String.format("\n%s\n",
// adding a tab to the beginning of every line to create a visual tree
String.format("%s: %s", key, children.get(key)).toString().replaceAll("(?m)(^)", "\t")));
}
return String.format("Trie [entry=%s, children=%s]", entry, childs);
}
static public class Entry<V> {
String prefix;
V value;
public Entry() {
}
public Entry(String p, V v) {
prefix = p;
value = v;
}
public String prefix() {
return prefix;
}
public V value() {
return value;
}
#Override
public String toString() {
return "Entry [prefix=" + prefix + ", value=" + value + "]";
}
}
}

get enum name from enum value [duplicate]

This question already has answers here:
Convert from enum ordinal to enum type
(15 answers)
Closed 7 years ago.
I've read a lot about how obtain the corresponding name of an enum from its value using java, but no example seems to work for me! What is wrong?
public class Extensions {
public enum RelationActiveEnum
{
Invited(0),
Active(1),
Suspended(2);
private final int value;
private RelationActiveEnum(final int value) {
this.value = value;
}
}
}
and in another class I use:
int dbValue = supp.ACTIVE;
Extensions.RelationActiveEnum enumValue(dbValue);
String stringName = enumValue.toString(); //Visible
// OR
int dbValuee = supp.ACTIVE;
String stringValue = Enum.GetName(typeof(RelationActiveEnum), dbValue);
I should work, right? but it doesn't!!!! it tells me that dbValue cannote be cast to RelationActiveEnum...
Say we have:
public enum MyEnum {
Test1, Test2, Test3
}
To get the name of a enum variable use name():
MyEnum e = MyEnum.Test1;
String name = e.name(); // Returns "Test1"
To get the enum from a (string) name, use valueOf():
String name = "Test1";
MyEnum e = Enum.valueOf(MyEnum.class, name);
If you require integer values to match enum fields, extend the enum class:
public enum MyEnum {
Test1(1), Test2(2), Test3(3);
public final int value;
MyEnum(final int value) {
this.value = value;
}
}
Now you can use:
MyEnum e = MyEnum.Test1;
int value = e.value; // = 1
And lookup the enum using the integer value:
MyEnum getValue(int value) {
for(MyEnum e: MyEnum.values()) {
if(e.value == value) {
return e;
}
}
return null;// not found
}
Since your 'value' also happens to match with ordinals you could just do:
public enum RelationActiveEnum {
Invited,
Active,
Suspended;
private final int value;
private RelationActiveEnum() {
this.value = ordinal();
}
}
And getting a enum from the value:
int value = 1;
RelationActiveEnum enumInstance = RelationActiveEnum.values()[value];
I guess an static method would be a good place to put this:
public enum RelationActiveEnum {
public static RelationActiveEnum fromValue(int value)
throws IllegalArgumentException {
try {
return RelationActiveEnum.values()[value]
} catch(ArrayIndexOutOfBoundsException e) {
throw new IllegalArgumentException("Unknown enum value :"+ value);
}
}
}
Obviously this all falls apart if your 'value' isn't the same value as the enum ordinal.
You could create a lookup method. Not the most efficient (depending on the enum's size) but it works.
public static String getNameByCode(int code){
for(RelationActiveEnum e : RelationActiveEnum.values()){
if(code == e.value) return e.name();
}
return null;
}
And call it like this:
RelationActiveEnum.getNameByCode(3);
What you can do is
RelationActiveEnum ae = Enum.valueOf(RelationActiveEnum.class,
RelationActiveEnum.ACTIVE.name();
or
RelationActiveEnum ae = RelationActiveEnum.valueOf(
RelationActiveEnum.ACTIVE.name();
or
// not recommended as the ordinal might not match the value
RelationActiveEnum ae = RelationActiveEnum.values()[
RelationActiveEnum.ACTIVE.value];
By if you want to lookup by a field of an enum you need to construct a collection such as a List, an array or a Map.
public enum RelationActiveEnum {
Invited(0),
Active(1),
Suspended(2);
private final int code;
private RelationActiveEnum(final int code) {
this.code = code;
}
private static final Map<Integer, RelationActiveEnum> BY_CODE_MAP = new LinkedHashMap<>();
static {
for (RelationActiveEnum rae : RelationActiveEnum.values()) {
BY_CODE_MAP.put(rae.code, rae);
}
}
public static RelationActiveEnum forCode(int code) {
return BY_CODE_MAP.get(code);
}
}
allows you to write
String name = RelationActiveEnum.forCode(RelationActiveEnum.ACTIVE.code).name();
In my case value was not an integer but a String.
getNameByCode method can be added to the enum to get name of a String value-
enum CODE {
SUCCESS("SCS"), DELETE("DEL");
private String status;
/**
* #return the status
*/
public String getStatus() {
return status;
}
/**
* #param status
* the status to set
*/
public void setStatus(String status) {
this.status = status;
}
private CODE(String status) {
this.status = status;
}
public static String getNameByCode(String code) {
for (int i = 0; i < CODE.values().length; i++) {
if (code.equals(CODE.values()[i].status))
return CODE.values()[i].name();
}
return null;
}
If you want something more efficient in runtime condition, you can have a map that contains every possible choice of the enum by their value. But it'll be juste slower at initialisation of the JVM.
import java.util.HashMap;
import java.util.Map;
/**
* Example of enum with a getter that need a value in parameter, and that return the Choice/Instance
* of the enum which has the same value.
* The value of each choice can be random.
*/
public enum MyEnum {
/** a random choice */
Choice1(4),
/** a nother one */
Choice2(2),
/** another one again */
Choice3(9);
/** a map that contains every choices of the enum ordered by their value. */
private static final Map<Integer, MyEnum> MY_MAP = new HashMap<Integer, MyEnum>();
static {
// populating the map
for (MyEnum myEnum : values()) {
MY_MAP.put(myEnum.getValue(), myEnum);
}
}
/** the value of the choice */
private int value;
/**
* constructor
* #param value the value
*/
private MyEnum(int value) {
this.value = value;
}
/**
* getter of the value
* #return int
*/
public int getValue() {
return value;
}
/**
* Return one of the choice of the enum by its value.
* May return null if there is no choice for this value.
* #param value value
* #return MyEnum
*/
public static MyEnum getByValue(int value) {
return MY_MAP.get(value);
}
/**
* {#inheritDoc}
* #see java.lang.Enum#toString()
*/
public String toString() {
return name() + "=" + value;
}
/**
* Exemple of how to use this class.
* #param args args
*/
public static void main(String[] args) {
MyEnum enum1 = MyEnum.Choice1;
System.out.println("enum1==>" + String.valueOf(enum1));
MyEnum enum2GotByValue = MyEnum.getByValue(enum1.getValue());
System.out.println("enum2GotByValue==>" + String.valueOf(enum2GotByValue));
MyEnum enum3Unknown = MyEnum.getByValue(4);
System.out.println("enum3Unknown==>" + String.valueOf(enum3Unknown));
}
}
This is my take on it:
public enum LoginState {
LOGGED_IN(1), LOGGED_OUT(0), IN_TRANSACTION(-1);
private int code;
LoginState(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public static LoginState getLoginStateFromCode(int code){
for(LoginState e : LoginState.values()){
if(code == e.code) return e;
}
return LoginState.LOGGED_OUT; //or null
}
};
And I have used it with System Preferences in Android like so:
LoginState getLoginState(int i) {
return LoginState.getLoginStateFromCode(
prefs().getInt(SPK_IS_LOGIN, LoginState.LOGGED_OUT.getCode())
);
}
public static void setLoginState(LoginState newLoginState) {
editor().putInt(SPK_IS_LOGIN, newLoginState.getCode());
editor().commit();
}
where pref and editor are SharedPreferences and a SharedPreferences.Editor

sql generated with hql query with composite user type

I'm using hibernate 3.6.1 and i have a strange behaviour on the sql generated by hql.
Here is the hql:
from Floor as floor where (floor.type != :var1)
type is a composite user type (see bottom) and is composed by two values a long and an int and a Type is different from another Type if at least one of the two values is different.
I want to extract all the floors with type different from a specified one, so all the floor with floor.oid<>oi1 OR floor.number1<>num1 where oi1 and number1 is from a specified Type. But the generated sql has an AND instead a OR:
select
floor0_.id as id0_,
floor0_.number as number0_,
floor0_.oid as oid0_,
floor0_.number1 as number4_0_
from
Floor floor0_
where
floor0_.oid<>?
and floor0_.number1<>?
i expect that the condition should be
floor0_.oid<>?
or floor0_.number1<>?
Floor implementation:
public class Floor {
private Long id;
private Integer number;
private Type type;
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
}
Type implementation:
public class Type implements CompositeUserType {
private Long oid;
public Long getOid() {
return oid;
}
public void setOid(Long oid) {
this.oid = oid;
}
private Integer number1;
public Integer getNumber1() {
return number1;
}
public void setNumber1(Integer number1) {
this.number1 = number1;
}
#Override
public String[] getPropertyNames() {
String[] names = {"oid", "number1"};
return names;
}
#Override
public org.hibernate.type.Type[] getPropertyTypes() {
BasicTypeRegistry registry = new BasicTypeRegistry();
org.hibernate.type.Type longType = registry.getRegisteredType(LongType.INSTANCE.getRegistrationKeys()[0]);
org.hibernate.type.Type intType = registry.getRegisteredType(IntegerType.INSTANCE.getRegistrationKeys()[0]);
org.hibernate.type.Type[] types = { longType, intType };
return types;
}
#Override
public Object getPropertyValue(Object component, int property)
throws HibernateException {
if (component == null) return null;
if (! (component instanceof Type)) {
throw new HibernateException("wrong component type");
}
Type type = (Type) component;
switch(property) {
case 0:
return type.oid;
case 1:
return type.number1;
default:
throw new HibernateException("wrong component type");
}
}
#Override
public void setPropertyValue(Object component, int property, Object value)
throws HibernateException {
// boh!!!
if (component == null) {
throw new HibernateException("set property invoked on a null instance");
}
if (! (component instanceof Type)) {
throw new HibernateException("set property invoked on a wrong component type");
}
Type type = (Type) component;
String valueString = value.toString();
switch(property) {
case 0:
type.oid = Long.parseLong(valueString);
case 1:
type.number1 = Integer.parseInt(valueString);
default:
throw new HibernateException("set property invoked on a wrong component type");
}
}
#Override
public Class returnedClass() {
// TODO Auto-generated method stub
return Type.class;
}
#Override
public boolean equals(Object x, Object y) throws HibernateException {
if(x == y) return true;
if (x == null && y != null) return false;
if (x != null && y == null) return false;
if(! (x instanceof Type) || ! (y instanceof Type)) {
return false;
}
Type xt = (Type)x;
Type yt = (Type)y;
return (xt.oid == yt.oid && xt.number1 == yt.number1);
}
#Override
public int hashCode(Object x) throws HibernateException {
if (x == null) {
return 0;
} else {
if (x instanceof Type) {
Type xt = (Type) x;
return xt.number1.hashCode() * 17 + xt.oid.hashCode();
} else {
throw new HibernateException("hashCode invoked on a non Type instance");
}
}
}
#Override
public Object nullSafeGet(ResultSet rs, String[] names,
SessionImplementor session, Object owner)
throws HibernateException, SQLException {
Type t = null;
if (!rs.wasNull()){
t = new Type();
Long id = rs.getLong(names[0]);
Integer number = rs.getInt(names[1]);
t.oid = id;
t.number1 = number;
}
return t;
}
#Override
public void nullSafeSet(PreparedStatement st, Object value, int index,
SessionImplementor session) throws HibernateException, SQLException {
Type t = (Type) value;
st.setLong(0, t.oid);
st.setInt(1, t.number1);
}
#Override
public Object deepCopy(Object value) throws HibernateException {
if (value == null)
return null;
Type oldType = (Type) value;
Type t = new Type();
t.setOid(oldType.getOid());
t.setNumber1(oldType.getNumber1());
return t;
}
#Override
public boolean isMutable() {
return false;
}
#Override
public Serializable disassemble(Object value, SessionImplementor session)
throws HibernateException {
return value.toString();
}
#Override
public Object assemble(Serializable cached, SessionImplementor session,
Object owner) throws HibernateException {
return cached;
}
#Override
public Object replace(Object original, Object target,
SessionImplementor session, Object owner) throws HibernateException {
return original;
}
}
is there something i'm wrong ?
Thanks for any help
It's certainly a bug in Hibernate, feel free to report it.
As a workaround you can use Critera for this query, it doesn't have this bug.
Also note that CompositeUserType is usually used to persist another class, not the same one, therefore your implementation of Type can be confusing, see 6.4.3. Custom types using org.hibernate.usertype.CompositeUserType.

Categories

Resources