Deserialize value that can be an integer or string - java

I am working with a legacy system that can have JSON that can either look like:
{"gauge": 1.0}
// or
{"gauge": "1.0-2.0"}
which is to say that gauge can be either an integer or a string. I want to be able to serialize and deserialize the value to and from the same type.
At first, I thought I could simply create an adapter for this:
public class Capabilities {
private Range gauge;
}
public class Range {
private int value;
private String range;
private boolean isRange;
public Range(int value) {
this.value = value;
this.isRange = false;
}
public Range(String value) {
this.range = range;
this.isRange = true;
}
public boolean isRange() {
return this.isRange;
}
public int getValue() {
return this.value;
}
public String getRange() {
return this.range;
}
}
Then I have RangeTypeAdapter that creates Range with the int/String value as appropriate.
However when I run gson.fromJson(str, Capabilities.class) I get:
Expected BEGIN_OBJECT but was STRING
I've ascertained that this is because the value of gauge in str is a wrapped in double-quotes and that fact that gauge is supposed to be a Range or anything other than a String means that it expects it to be an object.
Is there any way to expect Gson to expect a STRING for a particular class? Moreover, is there a better way handling a possible variance in primitive type?

I'm not aware if the Gson API gives a way to do this, but an option would be to try one conversion and if it fail, attempted the second one.
What I'm saying is to have a GaugeInt class that has gauge as an int field. And to have another class, GaugeString, that has gauge as a String field. Now we could attemp first conversion with say GaugeInt.class; if this causes an exception, we would try the second conversion with GaugeInt.class.

private String gauge = "";
public boolean isRange(){
return (gauge.indexOf("-")>-1);
}
public int getValue(){
if(isRange()){
return Integer.parseInt(gauge.split("-")[0]);
}else{
return Integer.parseInt(gauge);
}
}
public int getSecondValue(){
if(isRange()){
return Integer.parseInt(gauge.split("-")[1]);
}else{
return -1;
}
}
so by calling isRange() you will findout if its 1.0 or 1.0-2.0,
then based on that you can either
call getValue(),
or getValue() and getSecondValue()
which in the case of range will return second int and if not range will return -1 or pick other number to identify this case
no need for other adapters or so.
hope this helps you.

Related

Compare String in ENUM

I want to implement storing of enabled or disabled features into database row. When some String value is received from them the network I would like to compare it into ENUM.
ENUM:
public enum TerminalConfigurationFeatureBitString {
Authorize("authorize", 0), // index 0 in bit string
Authorize3d("authorize3d", 1), // index 1 in bit String
Sale("sale", 2), // index 2 in bit String
Sale3d("sale3d", 3), // index 3 in bit String
}
Map<TerminalConfigurationFeatureBitString, Boolean> featureMaps =
config.initFromDatabaseValue(optsFromDatabase);
featureMaps.get(transaction.transactionType);
The best way is to use featureMaps.get(TerminalConfigurationFeatureBitString.Sale);
But I don't know the incoming string what would be.
Now I get warning Unlikely argument type String for get(Object) on a Map<TerminalConfigurationFeatureBitString,Boolean>
Is there any other way to make a query into the ENUM without knowing the key?
In cases like these, I often find myself adding a static method getByX which does a lookup based upon a property of the enum:
public enum BitString {
//...
public static Optional<BitString> getByTransactionType(String transactionType)
{
return Arrays.stream(values())
.filter(x -> x.transactionType.equals(transactionType))
.findFirst();
}
}
Usage:
enum TransactionStatus
{
ENABLED, NOT_ENABLED, NOT_SUPPORTED
}
TransactionStatus status = BitString.getBygetByTransactionType(transaction.transactionType)
.map(bitString -> featureMaps.get(bitString))
.map(enabled -> enabled ? TransactionStatus.ENABLED : TransactionStatus.NOT_ENABLED)
.orElse(TransactionStatus.NOT_SUPPORTED);
Similar to #Michael's answer, you can just generate a static lookup map inside your enum which maps an enums transaction type to the actual enum:
private static final Map<String, TerminalConfigurationFeatureBitString> TRANSACTION_TYPE_TO_ENUM =
Arrays.stream(values()).collect(Collectors.toMap(
TerminalConfigurationFeatureBitString::getTransactionType,
Function.identity()
);
And then have a lookup method, also inside the enum:
public static TerminalConfigurationFeatureBitString getByTransactionType(String transactionType) {
TerminalConfigurationFeatureBitString bitString = TRANSACTION_TYPE_TO_ENUM.get(transactionType);
if(bitString == null) throw new NoSuchElementException(transactionType);
return bitString;
}
This in a way more performant than the mentioned answer, because the Map is created the first time the enum is loaded (So when it is the first time referenced). And thus the iteration happens only once. Also Maps have a rather fast lookup time so you could say that getting an enum this way works O(1) (when ignoring the initial computation time of O(n))
You can extend your enum with extra static method which will try to convert given String on enum item:
enum TerminalConfigurationFeatureBitString {
Authorize("authorize", 0), // index 0 in bit string
Authorize3d("authorize3d", 1), // index 1 in bit String
Sale("sale", 2), // index 2 in bit String
Sale3d("sale3d", 3); // index 3 in bit String
private final String value;
private final int index;
TerminalConfigurationFeatureBitString(String value, int index) {
this.value = value;
this.index = index;
}
public String getValue() {
return value;
}
public int getIndex() {
return index;
}
public static Optional<TerminalConfigurationFeatureBitString> fromValue(String value) {
for (TerminalConfigurationFeatureBitString item : values()) {
if (item.value.equals(value)) {
return Optional.of(item);
}
}
return Optional.empty();
}
}
In case option is not found, return Optional.empty(). If feature is not present it means String representation does not represent any feature. Usage:
public void test() {
EnumMap<TerminalConfigurationFeatureBitString, Boolean> featureMaps = new EnumMap<>(
TerminalConfigurationFeatureBitString.class);
Optional<TerminalConfigurationFeatureBitString> feature = TerminalConfigurationFeatureBitString.fromValue("authorize");
if (!feature.isPresent()) {
System.out.println("Feature is not foudn!");
} else {
Boolean authorize = featureMaps.get(feature.get());
if (authorize != null && authorize) {
System.out.println("Feature is enabled!");
} else {
System.out.println("Feature is disabled!");
}
}
}

Most efficient way to convert Enum values into comma seperated String

I have a java class in which I store an Enum.(shown at the bottom of this question) In this enum, I have a method named toCommaSeperatedString() who returns a comma separated String of the enums values. I am using a StringBuilder after reading some information on performance in this question here.
Is the way I am converting this enum's values into a commaSeperatedString the most efficient way of doing so, and if so, what would be the most efficient way to remove the extra comma at the last char of the String?
For example, my method returns 123, 456, however I would prefer 123, 456. If I wanted to return PROPERTY1, PROPERTY2 I could easily use Apache Commons library StringUtils.join(), however, I need to get one level lower by calling the getValue method when I am iterating through the String array.
public class TypeEnum {
public enum validTypes {
PROPERTY1("123"),
PROPERTY2("456");
private String value;
validTypes(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public static boolean contains(String type) {
for (validTypes msgType : validTypes.values()) {
if (msgType.value.equals(type)) {
return true;
}
}
return false;
}
public static String toCommaSeperatedString() {
StringBuilder commaSeperatedValidMsgTypes = new StringBuilder();
for(validTypes msgType : validTypes.values()) {
commaSeperatedValidMsgTypes.append(msgType.getValue() + ", ");
}
return commaSeperatedValidMsgTypes.toString();
}
}
}
I wouldn't worry much about efficiency. It's simple enough to do this that it will be fast, provided you don't do it in a crazy way. If this is the most significant performance bottleneck in your code, I would be amazed.
I'd do it something like this:
return Arrays.stream(TypeEnum.values())
.map(t -> t.value)
.collect(Collectors.joining(','));
Cache it if you want; but that's probably not going to make a huge difference.
A common pattern for the trailing comma problem I see is something like
String[] values = {"A", "B", "C"};
boolean is_first = true;
StringBuilder commaSeperatedValidMsgTypes = new StringBuilder();
for(String value : values){
if(is_first){
is_first = false;
}
else{
commaSeperatedValidMsgTypes.append(',');
}
commaSeperatedValidMsgTypes.append(value);
}
System.out.println(commaSeperatedValidMsgTypes.toString());
which results in
A,B,C
Combining this with the answers about using a static block to initialize a static final field will probably give the best performance.
The most efficient code is code that doesn't run. This answer can't ever change, so run that code as you have it once when creating the enums. Take the hit once, return the calculated answer every other time somebody asks for it. The savings in doing that would be far greater in the long term over worrying about how specifically to construct the string, so use whatever is clearest to you (write code for humans to read).
For example:
public enum ValidTypes {
PROPERTY1("123"),
PROPERTY2("345");
private final static String asString = calculateString();
private final String value;
private static String calculateString() {
return // Do your work here.
}
ValidTypes(final String value) {
this.value = value;
}
public static String toCommaSeparatedString() {
return asString;
}
}
If you have to call this static method thousand and thousand of times on a short period, you may worry about performance and you should first check that this has a performance cost.
The JVM performs at runtime many optimizations.
So finally you could write more complex code without added value.
Anyway, the actual thing that you should do is storing the String returned by toCommaSeperatedString and returned the same instance.
Enum are constant values. So caching them is not a problem.
You could use a static initializer that values a static String field.
About the , character, just remove it after the loop.
public enum validTypes {
PROPERTY1("123"), PROPERTY2("456");
private static String valueSeparatedByComma;
static {
StringBuilder commaSeperatedValidMsgTypes = new StringBuilder();
for (validTypes msgType : validTypes.values()) {
commaSeperatedValidMsgTypes.append(msgType.getValue());
commaSeperatedValidMsgTypes.append(",");
}
commaSeperatedValidMsgTypes.deleteCharAt
(commaSeperatedValidMsgTypes.length()-1);
valueSeparatedByComma = commaSeperatedValidMsgTypes.toString();
}
public static String getvalueSeparatedByComma() {
return valueSeparatedByComma;
}
I usually add a static method on the enum class itself:
public enum Animal {
CAT, DOG, LION;
public static String possibleValues() {
return Arrays.stream(Animal.values())
.map(Enum::toString)
.collect(Collectors.joining(","));
}
}
So I can use it like String possibleValues = Animal.possibleValues();

Sorting an object array based on a property

EDIT: Added some information.
I got an array of Objects. Each object has a name and a value. I need to sort the objects in descending order of those values, and print the names. I saw this easy solution but can't seem to apply it to my problem: http://www.mkyong.com/java/java-object-sorting-example-comparable-and-comparator/
The code compiles with no error but the array is not sorted at all. I know this because I know what the output should be i.e. the output should be something like var364, var200, var65 etc. and what i get is var1, var2, var3 etc.
I tried to strip the code of the irrelevant parts here:
Main class
print(data.preselection());
private void print (UnitRow preselectedUnitRow) {
out.printf("Variables after preselection: \n");
for (int i=0;i<PRESELECTION_LIMIT;i++) {
out.printf("%s, ",preselectedUnitRow.getUnitName(i));
}
}
Dataset (data)
private UnitRow data;
...
public UnitRow preselection() {
UnitRow standardDeviationUnits = new UnitRow(numberOfVariables);
for (int i=0;i<numberOfVariables;i++){
Unit unit = new Unit(1,variableNames[i],calculateStandardDeviation(i));
standardDeviationUnits.add(unit);
}
standardDeviationUnits.sort();
return standardDeviationUnits;
}
UnitRow
import java.util.Arrays;
public class UnitRow {
private Unit[] units;
private int count;
...
public void sort() {
Arrays.sort(units);
}
}
Unit
public class Unit implements Comparable<Unit>{
private NumberRow elements; //just a class with an array of doubles
private String name;
...
#Override
public int compareTo(Unit compareUnit) { //getValue returns a single type double number
int comparison = (int) (compareUnit.getValue(0) - getValue(0));
return comparison;
}
}
I am assuming my implementation of Comparable is wrong. Can you spot the problem?
I say this because I tested as following:
System.out.println(standardDeviationUnits.getValue(0,0));
standardDeviationUnits.sort();
System.out.println(standardDeviationUnits.getValue(0,0));
And the exact same value is returned.
It looks like reverse order
public int compareTo(Unit compareUnit) {
if (getValue(0) < compareUnit.getValue(0)) return 1;
else if (getValue(0) > compareUnit.getValue(0)) return -1;
return 0;
}
Try this.
Also note that in your compareTo, you unnecessarily wrote return 2; and wrote 3 if instead of 1 if-else.
If you are trying to sort as per names:
return compareUnit.name.compareTo(name);
else I have no idea what attribute your getValue(0) returns to you but still if you are trying to sort as per getValue(0):
return compareUnit.getValue(0)-getValue(0);

Java: how to convert from type A to type B?

I'm a java beginner and although I've looked for the topic both here and on Google I haven't found it. I'm sure it has to be there somewhere but it's me who doesn't know how to search. Anyway, here it is:
How can I write methods to convert from string/int/etc. to a class and vice-versa? I'd definitely like that my class conversion be automatic but I can live with less-than-perfect typecast. What I wouldn't be comfortable with is calling class("some string") or class.toString() for converting back and forth from string to class. I'd like it to be as seamless as possible. Here's an example:
I have a IsFound class that behaves like a boolean and I use it as a return type in a method; in the method body I return a string like "found" (instead of true). You may laugh at me for not using a Boolean but I want to play a little with a custom class/type. Here's some code
public class IsFound{
public boolean found; // field
public IsFound(String isFound_){
if(isFound_.equals("FOUND")){
found = true;
else found = false;
}
}
public String toString(){
if(found) return "found";
else return "not found";
}
}
This is the furthest I could get. I need the converter methods to/from string and for future references I'd like to know whether the converters are applicable for int, char or even other classes.
The solution to extend Boolean is only as a last resort, since I don't know what bloat I'm carrying along -- I want to create the class myself from 0.
EDIT:
I want to be able to use something like:
public IsFound parse(String substring_){
if(search(substring_, string) == true){
return FOUND; // or return "FOUND";
{
return NOTFOUND; // or return "NOT FOUND";
{
Currently it gives the error that can't convert from String to IsFound. I want to fill in this gap.
I'd also use an enum, here's one that gives you all of the functionality that is in your class.
public enum IsFound{
// each of these definitions are like calls to the IsFound constructor below
FOUND("found"),
NOT_FOUND("not found");
// string representation
private final String toString;
private IsFound(String isFound){
this.toString = isFound;
}
/**
* #Override
*/
public String toString(){
return toString;
}
// I think this is what you want. I'm not sure why you need this, but
// am including it as I think it gives you what you want. see example below
public static IsFound convert( String foundString ){
if( FOUND.toString.equals(foundString) ){
return FOUND;
}
else if( NOT_FOUND.toString.equals(foundString) ){
return NOT_FOUND;
}
else{
return null;
}
}
}
You can use this in the following ways:
private IsFound myFoundValue;
myFoundValue = IsFound.FOUND;
System.out.println(myFoundValue.toString()); // "found"
myFoundValue = IsFound.NOT_FOUND;
System.out.println(myFoundValue.toString()); // "not found"
switch( myFoundValue ){
case FOUND:
System.out.println("the value is FOUND");
break;
case NOT_FOUND:
System.out.println("the value is NOT_FOUND");
break;
default:
System.out.println("this should never happen");
break;
}
myFoundValue = IsFound.convert("found"); // IsFound.FOUND
System.out.println( myFoundValue.toString() ); // "found"
Your question smells like a classic XY Problem in that you appear to be barking up the wrong tree to find a solution to a problem that you may need to understand better. It's an anti-pattern to try to use Strings as a substitute for type, so you're far better off not doing this. For something like this, consider using either a boolean for a two-state type or an enum for a multi-state type.
e.g.,
public enum IsFound{
FOUND, NOT_FOUND, UNKNOWN
}
or...
public enum IsFound {
FOUND("Found"), NOT_FOUND("Not Found"), UNKNOWN("Unknown");
private String name;
private IsFound(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public String toString() {
return name;
}
}
in some other class.
private Map<Luggage, IsFound> lostLuggageMap = new HashMap<>();
The enum adds a compile-time type safety that Strings just don't have.
enums can have properties and behaviors (methods) that are extremely useful.
For conversion between "string" representations and POJO ( plain old java objects ), you may want to use serialization to / from a known text format such as JSON ( or XML ).
public class Search {
private boolean found;
// getters, setters, constructor
}
Serialization / Deserialization using Google's GSON library :
Search search = new Search();
search.setFound(true);
Gson gson = new Gson();
String json = gson.toJson(search);
// should output : { "found" : "true" }
// The opposite way , if json is a string equal to { "found" : "true" }
Gson gson = new Gson();
Search s = gson.fromJson(json, Search.class);
// s has found = true

Using Generics of Subclasses of Number to Create a Rollover Counter

I'm trying to create a counter that will rollover whenever it reaches a preset ceiling and resets back to its floor value upon reaching said ceiling. I have implemented the class and it works just fine. However, on my way to my solution, I wanted to experiment with Java Generics. I want to try and extend my counter so that it doesn't only use integers, but instead can use any type of number. I know that counters typically call for just the use of integers anyway, but I wanted to see if it could be done.
I figured that the code would be similar to below. However, java.lang.Number doesn't have a "generic" way of getting/setting its value. Do I need to create my own number class to enable this? Also, I know that if I do get this working, I need to alter my equals checks so that they have an error threshold for floating point values, this is more or less a modified version of my int counter with what I figured would work for generics.
Edit:
It's been suggested that I take a mapping approach where I store an integer counter and keep a increment value so that when I want to spit out a number, I just multiply my current count by the increment value. However, I don't believe this will fill my exact needs because I don't want to necessarily increment by the same amount every time. The main focus of this counter is more of a way to have a fixed range number that, when added to or subtracted from, knows how to handle wrapping back around.
I guess the best way to describe it (although probably improperly) would be like an Integer that automatically handles over/underflow.
package com.math;
public class GenericRolloverCounter<T extends Number> {
private T value;
private T lowValue;
private T highValue;
public GenericRolloverCounter(T l_startValue, T l_highValue) {
this.lowValue = l_startValue;
this.highValue = l_highValue;
this.value = l_startValue;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
public void increment(T valToIncrementBy) {
this.value += valToIncrementBy;
if (this.value > this.highValue) {
this.value = (this.lowValue + (this.value - (this.highValue + 1)));
}
}
public void increment() {
this.increment(1);
}
public void decrement(T valToDecrementBy) {
this.value -= valToDecrementBy;
if (this.value < this.lowValue) {
this.value = ((this.value + this.highValue + 1) - this.lowValue);
}
}
public void decrement() {
this.decrement(1);
}
#Override
public String toString() {
return Integer.toString(this.value);
}
}
You might want to also specify an amount by which to count. Default value would be 1.
You can get around some of this by using the Number method .doubleValue() and doing double arithmetic.
Here is one of the methods converted to use this idea.
public void decrement(double valToDecrementBy) {
double work = this.value.doubleValue();
work -= valToDecrementBy;
// should use some value related to incrementing amount
if ((this.value.doubleValue() - this.lowValue.doubleValue()) < 0.1D) {
work = ((this.value.doubleValue() + this.highValue.doubleValue() + 1) - this.lowValue.doubleValue());
}
// ... no way to put it back
}
But, there is still no way to put the value back that's clean and easy. Since 'Number' only has a few commonly used non-abstract subclasses, you could do some ugly instanceof stuff to store the value back. It would look something like this:
if (theValue instanceof Double) { // depends on it having a non-null value prior
theValue = (T)(new Double(work));
}
Or you could convert the starting values to double when you start and just work with doubles.
private double value;
private double lowValue;
private double highValue;
public GenericRolloverCounter(T l_startValue, T l_highValue) {
this.lowValue = l_startValue.doubleValue();
this.highValue = l_highValue.doubleValue();
this.value = l_startValue.doubleValue();
}
That does introduce the issues of incrementing floating point values and the rounding/evaluation problem there.
Oh ... and your toString() should be:
return value.toString();
To use the native toString() method on the T class.
#Crusher's comments suggest another way to do it. Map everything to 'int' and keep a multiplier. Here's some bits of code to show what I mean. (Thanks Crusher)
private int value;
private int lowValue;
private int highValue;
private double incr;
public GenericRolloverCounter(T l_startValue, T l_highValue, T incrementAmount) {
double incr = incrementAmount.doubleValue();
this.lowValue = Math.round(l_startValue.doubleValue() / incr);
this.highValue = Math.round(l_highValue.doubleValue() / incr);
this.value = Math.round(l_startValue.doubleValue() / incr);
}
public void increment(int valToIncrementBy) {
this.value += valToIncrementBy;
if (this.value > this.highValue) {
this.value = (this.lowValue + (this.value - (this.highValue + 1)));
}
}
#Override
public String toString() {
return String.valueOf(incr * this.value);
}

Categories