I'm trying to make an array with 2 values per item, like a value with a custom header, and, coming from Ruby, can't find a correct way to do this in Java.
This is for a REST-assured tests that i need to automate.
This is the method that i need to do, I mix the declaration of obj with some sort of ruby way to do it, so the necessity it's more clear:
private String[] getHeaders() {
String[] obj = [
'Signature' => this.getSignature(),
'Timestamp' => this.getTimestamp(),
];
if(getSessionToken() != null) {
obj.sessionToken = this.getSessionToken();
}
}
}
You can achieve that by creating a model. For example:
public class MyModel {
private String signature;
private String timestamp;
public MyModel() {
// constructor
}
public MyModel(String signature, String timestamp){
this.signature = signature;
this.timestamp = timestamp;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
}
Then create an array of your model. You can use:
private static final int MODEL_SIZE = 5;
private MyModel[] models = new MyModel[MODEL_SIZE];
if you already know the size of your array. Or you can use this approach below if you don't know the size of array yet:
private ArrayList<MyModel> models = new ArrayList<>;
private MyModel model;
// Then fill your models
// by using this way
model = new MyModel("My Signature", "My Timestamp");
models.add(model);
// or this way
model = new MyModel();
model.setSignature("My Signature");
model.setTimestamp("My Timestamp");
models.add(model);
Another way to achieve that without creating a model is by using HashMap. This is the example:
List<HashMap<String, String>> objects = new ArrayList<>();
HashMap<String, String> object = new HashMap<>();
object.put("signature", "My Signature");
object.put("timestamp", "My Timestamp");
objects.add(object);
Something like this I suspect is what you want.
class Headers{
public String signature;
public String timeStamp;
}
Headers[] header = new Headers[10];
You probably don't need getters and setters, but you can throw those in too.
Related
This question already has answers here:
Converting many 'if else' statements to a cleaner approach [duplicate]
(7 answers)
Closed 4 years ago.
I think this is a very common situation in web projects. Assume there is an entity such as:
//JAVA code
#Data
class Entity{
private String a;
private String aExt;
private String b;
private String bExt;
private String c;
private String cExt;
... something more ...
}
For some purpose, I need to get part of values from Entity according to a passed argument, like:
public ViewObject foo(Entity entity, String condition){
ViewObject vo = new ViewObject();
if("aRelated".equals(condition)){
vo.setValue1(entity.getA());
vo.setValue2(entity.getAExt());
}
else if("bRelated".equals(condition)){
vo.setValue1(entity.getB());
vo.setValue2(entity.getBExt());
}
else if(cRelated".equals(condition)){
vo.setValue1(entity.getC());
vo.setValue2(entity.getCExt());
}
... else statement if there are other values ....
return vo;
}
I know I can use switch-case statement to reduce some words in foo(), but there is no essential difference compared with if-else, especially when the Entity has many variables.
As a plain Example, foo() is only a view object builder, but my project is more complex which have many duplicated code with only different variable's name in each if-else statement.
How do I reduce the above duplicated code?
You can try creating two hash maps:
// name these properly!
HashMap<String, Function<Entity, String>> valueMap = new HashMap<>();
HashMap<String, Function<Entity, String>> extMap = new HashMap<>();
Add these KVPs:
// valueMap
"aRelated" - Entity::getA
"bRelated" - Entity::getB
"cRelated" - Entity::getC
// extMap
"aRelated" - Entity::getAExt
"bRelated" - Entity::getBExt
"cRelated" - Entity::getCExt
Now, you can do this without an if statement:
vo.setValue1(valueMap.get(condition).apply(entity));
vo.setValue2(extMap.get(condition).apply(entity));
Another option would be to use reflection:
import java.lang.reflect.Method;
import java.lang.reflext.InvocationTargetException;
...
public ViewObject foo(Entity e, String c) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
String[] methodNames = { "get" + c.substring(0,1).toUpperCase(), "get" + c.substring(0,1).toUpperCase() + "Ext" };
Method[] methods = { e.getClass().getDeclaredMethod(methodNames[0]), e.getClass().getDeclaredMethod(methodNames[1]) };
ViewObject vo = new ViewObject();
vo.setValue1((String)methods[0].invoke(e));
vo.setValue2((String)methods[1].invoke(e));
return vo;
}
Although I have to admit I personally like the map approach of the other answers more, just showing more options.
Use of a Map would do the trick:
class EntityPart {
String s;
String sExt;
}
class Entity {
Map<String,EntityPart> m = new HashMap<>();
m.add("aRelated",new EntityPart());
m.add("bRelated",new EntityPart());
....
}
public ViewObject foo(Entity entity, String condition) {
ViewObject vo = new ViewObject();
EntityPart ep = entity.m.get(condition);
vo.setValue1(ep.s);
vo.setValue2(ep.sExt);
return vo;
}
Make Entity as enum instead of class.
public enum Entity {
A("a", "aExt"), B("b", "bExt"), C("c", "cExt");
private final String name;
private final String text;
private Entity(String name, String text) {
this.name = name;
this.text = text;
}
public String getName() {
return name;
}
public String getText() {
return text;
}
public static Entity fromString(String raw) {
return LOOKUP.get(raw);
}
private static final Map<String, Entity> LOOKUP = new HashMap<>();
static {
for (Entity e : values()) {
LOOKUP.put(e.getName(), e);
}
}
}
And modify your foo method as
public ViewObject foo(String condition){
/*
* pass condition as "a", "b", "c" only not "aRelated", "bRelated", "cRelated"
*
*/
ViewObject vo = new ViewObject();
Entity e = Entity.fromString(condition);
if(null != e) {
vo.setValue1(e.getName());
vo.setValue2(e.getText());
}
return vo;
}
Edit: I was trying to simplify my problem at hand a little, but turns out, it created more confusion instead. Here's the real deal:
I am working with AWS's Java SDK for DynamoDB. Using the DynamoDBMapper class, I am trying to query DynamoDB to retrieve items from a particular table. I have several objects that map to my DynamoDB tables, and I was hoping to have a generic method that could accept the mapped objects, query the table, and return the item result.
Psudo-code:
#DynamoDBTable(tableName="testTable")
public class DBObject {
private String hashKey;
private String attribute1;
#DynamoDBHashKey(attributeName="hashKey")
public String getHashKey() { return this.hashKey; }
public void setHashKey(String hashKey)
#DynamoDBAttribute(attributeName="attribute1")
public String getAttribute1() { return this.attribute1; }
public void setAttribute1(String attribute1) { this.attribute1 = attribute1; }
}
public class DatabaseRetrieval {
public DatabaseRetrieval()
{
DBObject dbObject = new DBObject();
dbObject.setHashKey = "12345";
DBRetrievalAgent agent = new DBRetrievalAgent;
dbObject = agent.retrieveDBObject(dbObject.getClass(), dbObject);
}
}
public class DBRetrievalAgent {
public Object retrieveDBObject(Class<?> classType, Object dbObject)
{
DynamoDBQueryExpression<classType> temp = new DynamoDBQueryExpression<classType>().withHashKeyValues(dbObject);
return this.dynamoDBMapper.query(classType, temp);
}
}
Use a type witness within your method:
public <T> String getResult(Class<T> type) {
List<T> newList = new ArrayList<>();
//other code
}
Try this
ArrayList<T> newList = new ArrayList<>();
You can specify the type as T for your getResult() to make it generic (i.e., accepts any class) as shown below:
public <T> String getResult(T t) {
String result = "";
List<T> newList = new ArrayList<>();
// perform actions
return result;
}
I am using Jackson to prepare a JSON object to be inserted into ElasticSearch (ES is somewhat unrelated here). The object looks like:
class TimestampedCount {
private Date timestamp;
private Map<Long, Integer> counts;
}
The default behavior is, as expected, to convert the counts variable to an object. However, due to how I am storing the data in ES, I'd like to coerce the map to a byte[] or String field, without having to change the defined type. In other words, I want it stored differently from how it's being used. For example, if I convert it to a String, I'd expect something like the following in the final JSON:
{
"timestamp": 12355812312,
"counts": "{1: 15431, 2: 15423, 3: 1314}"
}
Is there a way to do this without having to write a custom serializer/deserializer?
You can simply add a 'getter' method which would convert the Map into suitable format. Here is an example returning a byte array:
public class JacksonGetter {
static class TimestampedCount {
private final Date timestamp;
private final Map<Long, Integer> counts;
public TimestampedCount(final Date timestamp, final Map<Long, Integer> counts) {
this.timestamp = timestamp;
this.counts = counts;
}
public Date getTimestamp() { return timestamp; }
#JsonProperty("counts")
public byte[] getCountsAsBytes() {
return counts.toString().getBytes();
}
}
public static void main(String[] args) throws JsonProcessingException {
final TimestampedCount timestampedCount = new TimestampedCount(
new Date(),
Collections.singletonMap(1L, 123));
final ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(timestampedCount));
}
}
Output:
{"timestamp":1450555085608,"counts":"ezE9MTIzfQ=="}
So I have these 4 variables
private final String PROG_DEPT = "PROGRAMMING/ENGINEERING";
private final String DES_DEPT = "DESIGN/WRITING";
private final String ART_DEPT = "VISUAL ARTS";
private final String SOUND_DEPT = "AUDIO";
What I want to be able to do is to get a string and compare it to the variable and then out put what the variable contains if it equals it.
For example if my string equals "ART_DEPT" then it check if there is a variable called ART_DEPT and then output "VISUAL ARTS"
I was thinking of putting it in a 2D String array or a list but I'm not really sure as to how to do what I want to do
The data type you're looking for is Map<String, String>.
Map<String, String> departmentNames = new HashMap<String, String>();
departmentNames.put("PROG_DEPT", "PROGRAMMING/ENGINEERING");
departmentNames.put("DES_DEPT", "DESIGN/WRITING");
//...etc...
//...
String dept = "PROG_DEPT";
String deptName = departmentNames.get(dept);
System.out.println(deptName); //outputs "PROGRAMMING/ENGINEERING"
A Map binds a unique key to a value. In this case both have the type String. You add bindings using put(key, value) and get the binding for a key using get(key).
I would go with an enum:
package com.stackoverflow.so18327373;
public class App {
public static void main(final String[] args) {
final String in = "DES_DEPT";
try {
final Departement departement = Departement.valueOf(in);
System.out.println(departement.getLabel());
} catch (final IllegalArgumentException ex) {
// in was not a known departement
System.err.println("Bad value: " + in);
}
}
public static enum Departement {
PROG_DEPT("PROGRAMMING/ENGINEERING"),
DES_DEPT("DESIGN/WRITING"),
ART_DEPT("VISUAL ARTS"),
SOUND_DEPT("AUDIO");
private final String label;
private Departement(final String label) {
this.label = label;
}
public String getLabel() {
return this.label;
}
}
}
then use valueOf()
You probably want to use some kind of Map, such as a HashMap<String,String>. I suggest you read the Javadocs for the Map interface and the HashMap class.
What you need to use is a Map.
private final Map<String,String> myMap= new HashMap<String,String>() ;
{
myMap.put("PROG_DEPT","PROGRAMMING/ENGINEERING");
myMap.put("DES_DEPT","DESIGN/WRITING");
myMap.put("ART_DEPT","VISUAL ARTS");
myMap.put("SOUND_DEPT","AUDIO");
}
Then use it in the following way:
String input= "ART_DEPT" ;
System.out.println( myMap.get(input) );
Try this
List<String> list=new ArrayList<>();
list.add("private final String PROG_DEPT = \"PROGRAMMING/ENGINEERING\";");
list.add("private final String DES_DEPT = \"DESIGN/WRITING\";");
list.add("private final String ART_DEPT = \"VISUAL ARTS\";");
list.add("private final String SOUND_DEPT = \"AUDIO\";");
String search="ART_DEPT";
for (String i:list){
if(i.contains(search)){
System.out.println(i.split("=")[1].replaceAll(";",""));
}
}
Live Demo here. You can do this using Map but to do that you have to create a map from these Strings.
Sounds like you are looking for reflection (or if you want to use a different data type instead of looking up a variable in a class then a Map<String, String>). Looks like the Map approach is well covered, so only because this is interesting to me, here is the reflection approach (not that this is not the best way to solve this problem, but since you asked for checking if a variable exists and then getting it's value)
import java.lang.reflect.Field;
public class SOQuestion {
private final String PROG_DEPT = "PROGRAMMING/ENGINEERING";
private final String DES_DEPT = "DESIGN/WRITING";
private final String ART_DEPT = "VISUAL ARTS";
private final String SOUND_DEPT = "AUDIO";
public static void main(String ... args) throws IllegalArgumentException, IllegalAccessException, InstantiationException {
System.out.println(reflectValue("ART_DEPT", SOQuestion.class));
System.out.println(reflectValue("COMP_DEPT", SOQuestion.class));
}
public static String reflectValue(String varible, Class thing) throws IllegalArgumentException, IllegalAccessException, InstantiationException {
Field[] fs = thing.getDeclaredFields();
for(int i = 0; i < fs.length; i++) {
if(fs[i].getName().equals(varible)) {
fs[i].setAccessible(true);
return (String) fs[i].get(thing.newInstance());
}
}
return null;
}
}
The first request to print "ATR_DEPT" will print VISUAL ARTS and the second request to the nonexistent "COMP_DEPT" will return null;
private String getStaticFieldValue(String fieldName){
String value = null;
try {
Field field = getClass().getDeclaredField(fieldName);
if (Modifier.isStatic(field.getModifiers())){
value = field.get(null).toString();
}
}
catch (Exception e) {
return null;
}
return value;
}
you have few options as mentioned above :
using a Map , the disadvantage of using a map for this case is that you will have to maintain it, it means that every time you will need to add/remove/edit one of your final static fields, you will have to edit the map as well.
using reflection as mentioned in this post, which is my favorite solution (the above code snippet)
Use the concept of Map
import java.util.HashMap;
import java.util.Map;
public class MajorMap {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Map<String, String> deptMap = new HashMap<String, String>();
deptMap.put("PROG_DEPT", "PROGRAMMING/ENGINEERING");
deptMap.put("DES_DEPT","DESIGN/WRITING");
deptMap.put("ART_DEPT","VISUAL ARTS");
deptMap.put("SOUND_DEPT","AUDIO");
System.out.println("ART_DEPT----->>"+deptMap.get("ART_DEPT"));
}
}
in scala, i have a need to serialize objects that are limited to a small set of basic types: array, list, map, set, int, boolean, etc. i want to be able to serialize and deserialize those in a way that preserves the type information in the serialized format. specifically, if i have serialized an Array[Any], i want to be able to deserialize it and only specify that the resulting object is Array[Any]. that is, i don't want to specify a structure definition for every single thing i'm going to serialize. at the same time it needs to be able to distinguish between int and long, tuple and array, etc.
for example:
val obj = Array[Any](...) // can have any basic types in here
val ser = serialize(obj)
val newObj = deserialize[Array[Any]](ser) // recovers the exact types from the original obj
json is not appropriate for this case because it has a many-to-one mapping of scala types to json types. i'm currently using java serialization but it's extremely slow. since i don't need to serialize any arbitrary object type, is there a faster alternative for my narrower use case?
I don't about speed or indeed availability of library support, but have you looked at ASN.1?
I'd use a simple interface like this:
public interface Serializer{
public <T> T deserialize(String serializedData);
public String serialize(Object data);
}
And an enum to implement it:
public enum StandardSerializer implements Serializer{
INTEGER("I", Integer.class, int.class){
#Override
protected Integer doDeserialize(final String stripped){
return Integer.valueOf(stripped);
}
},
STRING("I", String.class){
#Override
protected Object doDeserialize(final String stripped){
return stripped;
}
},
LIST("L", List.class){
#Override
protected String doSerialize(final Object data){
final Iterator<?> it = ((List<?>) ((List<?>) data)).iterator();
final StringBuilder sb = new StringBuilder();
if(it.hasNext()){
Object next = it.next();
sb.append(StandardSerializer
.forType(next.getClass())
.serialize(next));
while(it.hasNext()){
sb.append(',');
next = it.next();
sb.append(StandardSerializer
.forType(next.getClass())
.serialize(next));
}
}
return sb.toString();
}
#Override
protected Object doDeserialize(final String stripped){
final List<Object> list = new ArrayList<Object>();
for(final String item : stripped.split(",")){
list.add(StandardSerializer.forData(item).deserialize(item));
}
return list;
}
}
/* feel free to implement more enum entries */
;
private static final String DELIMITER = ":";
public static StandardSerializer forType(final Class<?> type){
for(final StandardSerializer candidate : values()){
for(final Class<?> supportedType : candidate.supportedClasses){
if(supportedType.isAssignableFrom(type)) return candidate;
}
}
throw new IllegalArgumentException("Unmapped type: " + type);
}
private final String prefix;
private final Class<?>[] supportedClasses;
private StandardSerializer(final String prefix,
final Class<?>... supportedClasses){
this.prefix = prefix;
this.supportedClasses = supportedClasses;
}
private String base64decode(final String removePrefix){
// TODO call one of the many base64 libraries here
return null;
}
private String base64encode(final String data){
// TODO call one of the many base64 libraries here
return null;
}
#SuppressWarnings("unchecked")
#Override
public final <T> T deserialize(final String serializedData){
return (T) doDeserialize(base64decode(removePrefix(serializedData)));
}
public static StandardSerializer forData(final String serializedData){
final String prefix =
serializedData.substring(0, serializedData.indexOf(DELIMITER));
for(final StandardSerializer candidate : values()){
if(candidate.prefix.equals(prefix)) return candidate;
}
throw new IllegalArgumentException("Unknown prefix: " + prefix);
}
protected abstract Object doDeserialize(String strippedData);
private String removePrefix(final String serializedData){
return serializedData.substring(prefix.length() + DELIMITER.length());
}
// default implementation calles toString()
protected String doSerialize(final Object data){
return data.toString();
}
#Override
public String serialize(final Object data){
return new StringBuilder()
.append(prefix)
.append(DELIMITER)
.append(base64encode(doSerialize(data)))
.toString();
}
}
Now here's how you can code against that:
List<?> list = Arrays.asList("abc",123);
String serialized = StandardSerializer.forType(list.getClass()).serialize(list);
List<?> unserialized = StandardSerializer.forData(serialized)
.deserialize(serialized);
(While you might choose a different format for serialization, using an enum strategy pattern is probably still a good idea)