Add null-like value to String in Java - java

I am writing test method like setTask(Task task). And Task object has several fields, e.g.
public String vehicle;
Method setTask should be used in different test-cases, so I'd like to have an options for this field to accept values:
null - the method should not do anything in this particulare case;
some string value - e.g. "", "Hello, World!", "Iso Isetta", ...
random - a value that indicates (as well as null indicates "no changes") that a random value should be selected for a drop-down list corresponding to this field.
So what can I do to make String to be SpecialString which could accept values null, random & some string value? (BTW: I don't want to set it to string value "RANDOM", and chech whether the value is equal to "RANDOM"-string)
UPDATE: I don't mean random like random value from a set of values, I mean random as well as null and this is for setTask() to handle random (select random from drop-down), and not to pass a random string from a set of values.
Pseudocode:
Task task = new Task();
task.vehicle = random; // as well as null
setTask(task)
in setTask(Task task):
if (task.vehicle == null) {
//skip
} else if (task.vehicle == random) {
// get possible values from drop-down list
// select one of them
} else {
// select value from drop-down list which is equal to task.vehicle
}

Don't assign a fixed String but use a Supplier<String> which can generate a String dynamically:
public Supplier<String> vehicleSupplier;
This, you can assign a generator function as you request:
static Supplier<String> nullSupplier () { return () -> null; }
static Supplier<String> fixedValueSupplier (String value) { return () -> value; }
static Supplier<String> randomSupplier (String... values) {
int index = ThreadLocalRandom.current().nextInt(values.length) -1;
return index > 0 && index < values.length ? values[index] : null;
}
In use, this looks like:
task.setVehicleSupplier(nullSupplier()); // or
task.setVehicleSupplier(fixedValueSupplier("value")); // or
task.setVehicleSupplier(randomSupplier("", "Hello, World!", "Iso Isetta"));
and you can get the String by
String value = task.vehicleSupplier().get();
or hide the implementation in a getter function
class Task {
// ...
private Supplier<String> vehicleSupplier;
public void setVehicleSupplier(Supplier<String> s) {
vehicleSupplier = s;
}
public String getVehicle() {
return vehicleSupplier != null ? vehicleSupplier.get() : null;
}
// ...
}

What you may want to do is to create an object that wraps a string as well as some information about whether or not it's a special value. Something along the lines of...
public class Special<T> {
public enum Type {
NOTHING, RANDOM, SPECIFIC
}
private final Type type;
private final T specificValue;
public Special(Type type, T specificValue) {
this.type = type;
this.specificValue = specificValue;
}
public Type getType() {
return type;
}
public T getSpecificValue() {
if (type != SPECIFIC) {
throw new IllegalStateException("Value is not specific");
}
return specificValue;
}
}
The class above could be used like so:
Special<String> a = new Special<>(Special.Type.NOTHING, null);
Special<String> b = new Special<>(Special.Type.SPECIFIC, "Hello");
if (b.getType() == Special.Type.RANDOM) {
// do something
}else if (b.getType() == Special.Type.SPECIFIC) {
String val = b.getSpecificValue();
// do something else
}
A slightly more polished variant of the thing above is probably the best way, but there is a way, a much uglier way, to do it using nothing but a String field.
What you could do is to have a "magical" string instance that behaves differently from all other string instances, despite having the same value. This would be done by having something like
static final String SPECIAL_VALUE_RANDOM = new String("random");
Note the use of the String constructor, which ensures that the string becomes a unique, non-interned instance. You can then say if (vehicle == SPECIAL_VALUE_RANDOM) { ... } (note the use of == instead of .equals()) to check if that specific instance (rather than any other string that says "random") was used.
Again, this is not a particularly good way of doing this, especially if you intend to do this more than once ever. I would strongly suggest something closer to the first way.

Related

What is better to use just one method with switch or 4 different methods?

I have a object and i get some fields from it, i made a method with a switch statement, the idea was make it generic and just call this method through parameters but now I´m not sure.
The options are
private String getCode(Row row, String code) {
String result;
switch (code) {
case code1:
result = row.getString("constant1");
break;
case code2:
result = row.getString(constant2);
break;
case code3:
result = row.getString(constant3);
break;
case code4:
result = row.getString(constant4);
break;
default:
result = null;
}
return result;
}
or
private String getcode1(Row row){
return row.getString("constant1")
}
private String getcode1(Row row){
return row.getString("constant2")
}
private String getcode1(Row row){
return row.getString("constant3")
}
private String getcode1(Row row){
return row.getString("constant4")
}
I wand to use the better way, I´m a little confuse
The answer is neither of the them.
What you have here is a value conversion process. How this works? Well, as far I understand, you need to store the data in form of key-value pair where key must be unique. So this is the definition of a HashMap in java.
Also, because you are using Switch I'm assuming that you can identify your data with some unique key. This meas for each code there is only one constant. But how we can apply this to my issue? Well, I think you have a collection of data from where you extracted a single row. Now, from this row you want to access to a value (lets call it codeValue) using a constant, but to get this constant you need a code. Like this: code->constant->codeValue
How can I implement this??
Well, we gonna need a HasMap() called constants, which defines its keys a codes and the values as constants. Now you easily get each constant if you know its code. Obviously, if you get the constant you can also get the codeValue of each `row, like this:
public class TestClass {
public static void main(String[] args) {
// Create a HashMap object called constants
Map<String, String> constants = new HashMap<String, String>();
// Add keys and values (code, constant)
constants.put("code1", "constant1");
constants.put("code2", "constant2");
constants.put("code3", "constant3");
constants.put("code4", "constant4");
System.out.println(constants);
Row row = loadRow();
String code = loadCode();
//How to use it
String result = getCodeValue(row, code);
System.out.println(result);
}
// Now you get the code from the Map
private String getCodeValue(Row row, String code) {
return row.getString(constants.get(code));
}
}
In case your input code is different than constant, I will suggest the following approach. Create an Enum mapping code and constant.
public enum Mapping {
MAPPING_FIRST("code1", "constant1"),
MAPPING_SECOND("code2", "constant2");
private String code;
private String constant;
// constructor and getters
public static Mapping getMappingFromCode(String code){
return Arrays.stream(Mapping.values())
.filter(mapping -> mapping.getCode().equals(code))
.findFirst()
.orElse(null);
}
}
Now, create a method to access value from row.
private String getValue(Row row, String code) {
Mapping mapping = Mapping.getMappingFromCode(code);
if(mapping == null){
return null;
}
return row.getString(mapping.getConstant());
}
This question is little bit to much, but I will try to explain best I could. For me second option is no no at all. Why? You are making methods that you will have to sort out with some if/else statements anyway, for example:
if (code.equals(code1))
someString = getcode1(row);
else if (code.equals(code2))
somestring = getcode2(row);
else if (code.equals(code3))
someString = getcode3(row);
else
someString = getcode4(row);
Why not use this:
if (code.equals(code1))
someString = row.getString("content1");
else if (code.equals(code2))
somestring = row.getString("content2");
else if (code.equals(code3))
someString = row.getString("content3");
else
someString = row.getString("content4");
The first one I can see being used, but there is alternative there. Give us entire minimal requirement code with entire class and methods and we could help you far more than using these snippets of code.
Create an enum for mapping of code and constant. In that enum, create a generic method where you can get code just passing through parameter.
public enum MyEnum {
CODE1("constant1"), CODE2("constant2");
private String constant;
public String getConstant() {
return constant;
}
private MyEnum(String constant) {
this.constant = constant;
}
private static String getConstant(String code) {
return Arrays.stream(MyEnum.values()).filter(mapping -> mapping.name().equalsIgnoreCase(code))
.map(e -> e.getConstant()).findAny().orElse(null);
}
public static String getCode(Row row, String code) {
String constant = getConstant(code);
return constant != null ? row.get(constant) : null;
}
}
You can get code from row object by calling genric method getCode().
MyEnum.getCode(row, "code1")

Passign attribute name as parameter automatically in Java-8

I would like to have a method to validate fields kind of
protected void validate(String field, String fieldName){
if (field==null || field.isEmpty){
throw new IllegalArgumentException("Parameter " + fieldName + " cannot be empty");
}
}
and use in my class for example
class Foo {
private String x;
private String y;
...
public void validateAll(){
validate(x, "x");
validate(y, "y");
}
}
It would be great to use in this way
public void validateAll(){
validate(x);
validate(y);
}
and let the compiler pass the name of the variable automatically to validate(field, fieldName) method
How can I achive this in Java-8 ?
You can achieve this in Java by abandoning the idea of having java classes with fields, and instead having a Map which maps Column objects to values. From a usage standpoint, it would look roughly like this:
public static final Column<String> X_COLUMN = new Column<>( "x", String.class );
public static final Column<String> Y_COLUMN = new Column<>( "y", String.class );
public static final Table FOO_TABLE = new Table( "Foo", X_COLUMN, Y_COLUMN, ... );
...
Row fooRow = new Row( FOO_TABLE );
fooRow.setFieldValue( X_COLUMN, "x" );
String x = fooRow.getFieldValue( X_COLUMN );
for( Column<?> column : fooRow.getTable().getColumns() )
doSomethingWithField( fooRow, column );
private static <T> void doSomethingWithField( Row row, Column<T> column )
{
T value = row.getFieldValue( column );
...do something with the field value...
}
Since a value passed as argument to a method bears no information about the field it originated from, if it was read from a field at all, you can’t reconstruct this information. However, since your intent to verify fields, the desired operation is possible when processing the fields in the first place, rather than their contained values:
class Foo {
private String x;
private String y;
//...
public void validateAll() {
for(Field f: Foo.class.getDeclaredFields()) {
if(!Modifier.isStatic(f.getModifiers()) && !f.getType().isPrimitive()) try {
Object o=f.get(this);
if(o==null || o.equals(""))
throw new IllegalArgumentException(f.getName()+" cannot be empty");
} catch(ReflectiveOperationException ex) { throw new AssertionError(); }
}
}
}
The general problem of this approach is that by the time validateAll() reports a problem, the Foo instance already contains the illegal state. It’s preferable to reject invalid values right when they are attempted to set for a property. In that case, the parameter name of the method might not be available reflectively, however, when a method named setX throws an IllegalArgumentException (as would be indicated by the stack trace), there is no need for an additional meta information in the message…

Array of set methods - Java

I am busy with a project that extracts data from a xml file and displays it in a word document. I have created a method for this extraction, but I want to simplify it by using an array of methods.
This is just an example of how I test for certain information at the moment:
for (int i = 0; i < nodeMap.getLength(); i++) {
Node node = nodeMap.item(i);
if (node.getNodeName().equalsIgnoreCase("maximumRedeliveries")) {
if (node.getNodeValue().startsWith("{{")) {
retryLogic.setMaximumRedeliveries(extractPropertyName(node.getNodeValue(), propFileLocation));
} else {
retryLogic.setMaximumRedeliveries(node.getNodeValue());
}
}
if (node.getNodeName().equalsIgnoreCase("asyncDelayedRedelivery")) {
if (node.getNodeValue().startsWith("{{")) {
retryLogic.setAsyncDelayedRedelivery(extractPropertyName(node.getNodeValue(), propFileLocation));
} else {
retryLogic.setAsyncDelayedRedelivery(node.getNodeValue());
}
}
}
I am aiming to create an array for the if statement values, for example "maximumRedeliveries" and "asyncDelayedRedelivery" and an array for their corresponding methods, for example setMaximumRedeliveries(),setAsyncDelayedRedelivery(). I am unsure of how to create an array of methods, or if it's even possible?
This problem differs form Java - Creating an array of methods, because I use set methods and don't know how to implement it in that way.
First, ensure that extractPropertyName takes names with and without curly braces, and behaves like this:
String extractOptionalPropertyName(String name, String propFileLocation) {
return name..startsWith("{{") ? extractPropertyName(name, propFileLocation) : name;
}
This moves conditionals from your XML processing code into a helper:
String nodeName = node.getNodeName();
if (nodeName.equalsIgnoreCase("maximumRedeliveries")) {
retryLogic.setMaximumRedeliveries(extractOptionalPropertyName(node.getNodeValue(), propFileLocation));
} else if (nodeName.equalsIgnoreCase("asyncDelayedRedelivery")) {
retryLogic.setAsyncDelayedRedelivery(extractOptionalPropertyName(node.getNodeValue(), propFileLocation));
} ... // and so on
With these changes in place, you can follow the recipe from this other Q&A and make a Map<String,ValSetter> objects, like this:
interface ValSetter {
void set(RetryLogic logic, String val);
}
// The map can be made static in a class
Map<String,ValSetter> setterForName = new HashMap<>();
{ // Initializer block
setterForName.put("maximumredeliveries", new ValSetter() {public void set(RetryLogic logic, String val) { logic.setMaximumRedeliveries(val);}} );
setterForName.put("asyncrelayedredelivery", new ValSetter() {public void set(RetryLogic logic, String val) { logic.setAsyncDelayedRedelivery(val);}} );
}
Now your XML handler could look like this:
String nodeName = node.getNodeName();
ValSetter setter = setterForName.get(nodeName.toLowerCase());
if (setter != null) {
String val = extractOptionalPropertyName(node.getNodeValue(), propFileLocation);
setter.set(retryLogic, val);
} else {
// report an error
}

Suspicious call to Collection.contains method in ArrayList

I am getting a warning that watchStore.contains(s) is a suspicious call to java.util.Collection#contains. How can I fix it? I want to use contains() to find a particular object with the matching serial number.
public Watch findWatchBySerialNumber(long srch) {
long s = srch;
Watch watch = null;
for(int i = 0; i < watchStore.size(); i++) {
watch = watchStore.get(i);
if(watchStore.contains(s)) {
System.out.print("item found");
return watch;
}
}
System.out.print("item not found");
return null; // watch is not found.
}
Presuming that Watch is the class, watchStore is a List<Watch>, and that a field serialNo exists on Watch...
public Optional<Watch> findWatchBySerialNumber(long serial) {
return watchStore.stream()
.filter(w -> w.getSerialNo() == serial)
.findFirst();
}
If you're not using Java 8, the code is close, but a bit more dangerous since you have the chance to return null. If you can use Guava's Optional, that'd be a better choice here.
public Watch findWatchBySerialNumber(long serial) {
for(Watch w : watchStore) {
if(w.getSerialNo() == serial) {
return w;
}
}
return null;
}
Your contains isn't going to work since your list doesn't contain Longs, it contains Watchs. This is also why the compiler sees it as dubious; contains accepts an Object but it will return false if what you're looking for doesn't have a comparable equals for what's in your list.
You have to iterate over the entirety of your collection to find it in this scenario, especially since you're looking for a specific property on those objects as opposed to a specific, easy-to-provide value.
please how can I fix that. I want to use the contain() to find a
particular object with the matching serial number.
In that case override Watch's equals() to use serialNumber field for comparison.
Then add constructor that accepts serialNumber.
public class Watch {
private final long serialNumber;
public Watch(long serialNumber) {
this.serialNumber = serialNumber;
}
#Override
public boolean equals(Object obj) {
return obj == this ||
(obj instanceof Watch && ((Watch)obj).serialNumber == serialNumber);
}
#Override
public int hashCode() {
return (int)serialNumber;
}
}
Replace if(watchStore.contains(s)){ with if(watchStore.contains(watchToFind)){ where Watch watchToFind = new Watch(s);
you can use contains method from org.apache.commons.lang.ArrayUtils package.
Checks if the value is in the given array.
The method returns false if a null array is passed in.
Parameters:
array the array to search through
valueToFind the value to find
Returns:
true if the array contains the object
long [] imageHashes= {12l,13l,14l,15l};
System.out.println(ArrayUtils.contains(imageHashes, 13l));

Reflection improvements to access field secret, when field type is unknown

I am learning about Security and looking at storing secrets in the clear.
When I retrieve the contents of a private field, it returns an Object. My mal code correctly assumes and casts the Object as an int, however if I change/parse the field type from int secretInt = 42; to String secretInt = (new Integer(42).intValue()).tostring the Mal code fails miserably.
EDIT: The unusual wrapping (new Integer(42).intValue()).tostring is created by a automated parser, it is not written by a programmer.
how can I add robustness to Mal code so the assumption of the returned type is removed. Is this possible? I need to use this value as int param.
EDIT: 'String' is one example but the parser may choose a data-structure as suitably-inappropriate as byte[], char[].
This is my non-compliant code.
public final class SecretInClear implements Check4SecretsInClear {
//Non-Compliant: Secret int stored in Clear.
private final int secretInt = 42;
#Override
public boolean isSecretInt(int check) {
return (check == secretInt);
}
}
This is my mal code.
public class ReadClearSecret implements Tester {
//Example of running
public static void main(String[] args) {
String testResult = new ReadClearSecret().test(new SecretInClear());
System.out.println(testResult);
}
private Object readPrivateField(Object o, String fieldName) {
try {
Field field = o.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(o);
} catch(Exception e) {
throw new IllegalArgumentExecption(e);
}
#Override
public String test(final Object secretChecks) {
final Check4SecretsInClear check4SecretsInClear = (Check4SecretsInClear)secretChecks;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("class:").
append(check4SecretsInClear.getClass().getSimpleName());
boolean bSecretInt = false;
String s = "";
try {
int secretInt = (Integer)readPrivateField(check4SecretsInClear,"secretInt"); //<<< HERE! It's cast as an integer!!!
bSecretInt = check4SecretsInClear.isSecretInt(secretInt); //<<< HERE! Param must be an int.
} catch (ClassCastException e) {
s = "," + e.getClass().getSimpleName();
} finally {
stringBuilder.append(" int:").append(bSecretInt).append(s);
s = "";
}
return stringBuilder.toString();
}
}
EDIT:
Instead of casting (int) from readPrivateField(). Instead I extract the string value String.valueOf(Object) or Object.toString(). I can then pass that string as a int param with new Integer(stringValue).
HOWEVER: If the parser chooses to represent secretInt as type byte[] the string value will be nuts and the mal code will be pwned. Any suggest to produce robustness against this?
The return type of Field.get() is an Object. If you need to know its class you can call Field.getType() but usually you don't need to know the type, only the information contained.
You could just do
String secret = "42";
or
#Override
public boolean isSecretInt(int check) {
return check / 6.0 == 7;
}
Don't use Integer to compare values, as this compare objects, not their values.
A shorter implementation
private Object readPrivateField(Object o, String fieldName) {
try {
Field field = o.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(o);
} catch(Exception e) {
throw new IllegalArgumentExecption(e);
}
}
BTW: "What do you get if you multiply 6 by 9", for those who have read the Hitchhiker's Guide to the Galaxy.
System.out.println(Integer.toString(6 * 9, 13));
prints
42
;)
You can always use:
String value = String.valueOf(field.get(o));
To avoid caring what the type is and always give you a String.
CREDIT: Peter Lawrey
If it is suitably inappropriate you know the answer, it can't be don't generically in code. You need to read the byte code of isSecretInt to see how it is done, and for that a human is the simplest solution ;) –

Categories

Resources