Java Refelection : find field's name and value - java

I have a class
like below
public class SampleReflection {
public static final String TWO_name = "html";
public static final String TWO_find = "css";
public static final String ONE_KEY_java = "java";
public static final String ONE_KEY_jsp = "jsp";
public static final String ONE_KEY_oracle = "oracle";
public static final String ONE_KEY_spring = "spring";
public static final String ONE_KEY_struts = "struts";
}
I would like to get all the fields which starts with ONE_KEY and their value.
because the ONE_KEY_xxx can be of any numbers.
how to do this in java reflection or any other way in java ?
thanks

You can use SampleReflection.class.getDeclaredFields(), iterate over the result and filter by name. Then call field.get(null) to get the value of the static fields. If you want to access non-public fields as well you might have to call first.setAccessible(true) (provided the security manager allows that).
Alternatively you could have a look at Apache Common's reflection utilities, e.g. FieldUtils and the like.
Depending on what you actually want to achieve there might be better approaches though, e.g. using a map, enums etc.
In your case where you have static fields using an enum might be a better way to go.
Example:
enum SampleFields {
TWO_name("html"),
TWO_find("css"),
ONE_KEY_java("java"),
ONE_KEY_jsp("jsp");
ONE_KEY_oracle("oracle"),
...;
private String value;
private SampleFields(String v) {
value = v;
}
}
Then iterate over SampleFields.values() and filter by name.
Alternatively, if that fits your needs, you could split the names and pass a map to the enum values, e.g.
enum SampleFields {
TWO(/*build a map "name"->"html","find"->"css")*/ ),
ONE_KEY(/*build a map "java"->"java","jsp"->"jsp", ...*/);
private Map<String, String> values;
private SampleFields(Map<String, String> map) {
values = map;
}
}
Then get the enum values like this: SampleFields.valueOf("ONE_KEY").get("java")

Thanks for the answer,
this is what i was looking for,
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class SampleReflection {
public static final String TWO_name = "html";
public static final String TWO_find = "css";
public static final String ONE_KEY_java = "java";
public static final String ONE_KEY_jsp = "jsp";
public static final String ONE_KEY_oracle = "oracle";
public static final String ONE_KEY_spring = "spring";
public static final String ONE_KEY_struts = "struts";
public static void main(String[] args) {
Class<?> thisClass = null;
Map<String,String> keyValueMap = new HashMap<String,String>();
try {
thisClass = Class.forName(SampleReflection.class.getName());
Field[] aClassFields = thisClass.getDeclaredFields();
for(Field f : aClassFields){
String fName = f.getName();
if(fName.contains("ONE_KEY")){
keyValueMap.put(fName, (String)f.get(SampleReflection.class));
}
}
for (Map.Entry<String, String> entry : keyValueMap.entrySet())
{
System.out.println(entry.getKey() + "=" + entry.getValue());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

Related

How to use HashMaps in RestAssured if I want to extract the JSON response value and avoid using static variables at the beginning?

Right now I am using the JSON path function to get the JSON response values like placeid, profileid and then am declaring that as static, because I need to use those variables in clickProfile() and clickPlace() functions. Going forward I will have a lot of values like placeid, profileid, contentid etc and I want to avoid those declaring as static String at the beginning. Instead I want to use the Maps concept here going forward and want to use it from framework Utility. 
I am new to HashMaps. Can someone help me here in implementing the Maps concept here?
public static String placeid;
public static String profileid;
public void extractplaceId()
{
placeid = getJsonPath("results.place_id");
System.out.println(placeid);
}
public void extractpleId()
{
profileid = getJsonPath("results.profile_id");
System.out.println(profileid);
}
public Response clickProfile() throws IOException
{
config.setProperty("APIendPoints.properties");
PROFILE_URL = config.getConfig().getProperty("CLICK_PROFILE") + profileid + ".json";
response = requestSpec.when().get(PROFILE_URL);
return response;
}
public Response clickPlace() throws IOException
{
config.setProperty("APIendPoints.properties");
PLACE_URL = config.getConfig().getProperty("CLICK_PLACE") + placeid + ".json";
response = requestSpec.when().get(PLACE_URL);
return response;
}
Framework Utility:
public String getJsonPath(String key)
{
String resp = response.asString();
JsonPath js = new JsonPath(resp);
return js.get(key).toString();
}
I assume that you want something like a pack of all variables that you want to save and retrieve later. My POC below just work correctly for single thread, not sure about multiple threads.
A class to add/get/edit/remove variables. It wraps a Map to do the trick.
public class EnvironmentVariable {
private static final Map<String, Object> variables = new HashMap<>();
public static void add(String key, Object value) {
variables.put(key, value);
}
public static Object get(String key) {
return variables.get(key);
}
public static void edit(String key, Object value) {
variables.put(key, value);
}
public static Object remove(String key) {
return variables.remove(key);
}
}
ExtractUtil class to provide functions extract or extractAndSave
public class ExtractUtils {
public static Object extractFrom(Response res, String query){
return res.jsonPath().get(query);
}
public static void extractAndSave(Response res, String query, String key) {
Object value = res.jsonPath().get(query);
EnvironmentVariable.add(key, value);
}
}
Test client
public class TestClient {
public Response test() {
return given().get("https://auto-test-challenges.herokuapp.com/challenge3restassured");
}
#Test
void name() {
Response res = test();
ExtractUtils.extractAndSave(res, "data.key1.number", "key1_number");
given().log().all().get("https://postman-echo.com/get?a=" + EnvironmentVariable.get("key1_number"));
}
#Test
void name2() {
Response res = test();
int key2_number = (Integer) ExtractUtils.extractFrom(res, "data.key2.number");
EnvironmentVariable.add("key2_number", key2_number);
given().log().all().get("https://postman-echo.com/get?a=" + EnvironmentVariable.get("key2_number"));
}
}
Because I want my map can save any object, so that I use Map<String,Object>. It requires casting to get value from the map, like int key2_number = (Integer) ExtractUtils.extractFrom(res, "data.key2.number");

how to call methods in Springboot application? [duplicate]

This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
how to call methods in Springboot [duplicate]
Closed 2 years ago.
When using Spring DI via "#Autowired" gives NPE and as per comments if I tried giving "#Component" to TestLogger but gives "Consider defining a bean of type 'java.lang.String' in your configuration."
Project LogTester
#SpringBootApplication
public class TestSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(TestSpringBootApplication.class, args);
System.out.println("TestSpringBootApplication !! ");
}
}
public class TestLogger {
private static final String KEY_VALUE_DELIMITER = "=";
private static final String KEY_VALUE_PAIR_SEPARATOR = ", ";
private static final String DOUBLE_QUOTES = "\"";
private static final String ESCAPED_DOUBLE_QUOTES = "\\\\\"";
private static final String MESSAGE_FIELD_KEY = "message";
private static final String THROWABLE_CLASS_FIELD_KEY = "throwableClassName";
private static final String THROWABLE_MESSAGE_FIELD_KEY = "throwableMessage";
private static final String STACK_TRACE_FIELD_KEY = "stackTrace";
private static final String STACK_TRACE_ELEMENT_SEPARATOR = ",";
private final Map<String,Object> _fieldsMap = new LinkedHashMap<>();
public TestLogger withField(String key, Object value) {
_fieldsMap.put(key, value);
return this;
}
private TestLogger(String message) {
withField(MESSAGE_FIELD_KEY, message);
}
#Override
public String toString() {
final StringBuilder sb = new StringBuilder();
boolean firstIteration = true;
for (Map.Entry<String, Object> field : _fieldsMap.entrySet()) {
String key = field.getKey();
String value;
value = Objects.toString(field.getValue(), StringUtils.EMPTY);
// escape all double quotes
value = StringUtils.replace(value, DOUBLE_QUOTES, ESCAPED_DOUBLE_QUOTES);
// surround the value in double quotes if it contains a space
if (value.contains(StringUtils.SPACE)) {
value = DOUBLE_QUOTES + value + DOUBLE_QUOTES;
}
if (firstIteration) {
firstIteration = false;
} else {
sb.append(KEY_VALUE_PAIR_SEPARATOR);
}
sb.append(key).append(KEY_VALUE_DELIMITER).append(value);
}
return sb.toString();
}
}
Project B is just one main class to invoke the method of Project A LogTester
#Component
public class MainClass {
#Autowi
red
private static TestLogger obj;
public static void main(String[] args) {
System.out.println("HI");
System.out.println(obj.withField("key", "89899"));
}
}
pom.xml
<dependency>
<groupId>com.test</groupId>
<artifactId>logTester</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
Output is below when
Exception in thread "main" java.lang.NullPointerException
at test.MainClass.main(MainClass.java:24)
In LoggerTest keyLogger is null because it is not injected. Please add the annotation #Component to LoggerTest to enable autowiring and inject LoggerTest via #Autowired to ApplicationRunnerBean (and not via new LoggerTest()).

Java outer class static initialization

I have a problem with Java static initialization. What I want to do is some type checking with generic constants and to translate between types and type names. So I have some typed constants in interface MC and a hash map in inner class Type to translate names to types. Now when I call MC.Type.getValue("MInteger") the inner class Type is initialized but not the static constants in the outer class MC so the return value is null. How can I get Java to initialize these constants? I could do
static { Type<?> dummy = MC.MBoolean; }
in class Type but isn't there some better way to do this. Or am I doing this totally wrong.
import java.util.HashMap;
import java.util.Map;
interface MC {
public static final Type<Boolean> MBoolean = new Type<>("MBoolean");
public static final Type<Integer> MInteger = new Type<>("MInteger");
public static class Type<T> {
private static final Map<String, Type<?>> types = new HashMap<>();
private final String name;
private Type(String name) {
this.name = name;
types.put(name, this);
}
public String getName() {
return name;
}
public static Type<?> getValue(String name) {
return types.get(name);
}
}
}
public class Main {
public static void main(String[] args) {
System.out.println(MC.Type.getValue("MInteger"));
MC.MBoolean.getName();
System.out.println(MC.Type.getValue("MInteger"));
}
}
Since all Type instances are included in your MC class, a very direct approach to solving this problem would be to move registration of the class with the Type.types map from the constructor of Type to its static initializer:
private static final Map<String, Type<?>> types = new HashMap<>();
static {
types.put(MBoolean.getName(), MBoolean);
types.put(MInteger.getName(), MInteger);
}
private Type(String name) {
this.name = name;
// removed types.put(name, this); from here
}
Demo.
You can use either static initializer block:
private static final Map<String, Type<?>> types = new HashMap<>();
static {
types.put(MC.MBoolean.getName(), MC.MBoolean);
types.put(MC.MInteger.getName(), MC.MInteger);
}
or double brace initialization:
private static final Map<String, Type<?>> types = new HashMap<>() {{
put(MC.MBoolean.getName(), MC.MBoolean);
put(MC.MInteger.getName(), MC.MInteger);
}};
First curly braces creates new anonymous subclass of HashMap, second curly braces are instance initializer block which is executed at construction time (arg-less constructor for anonymous classes).
The Constructor won't initialize unless you explicitly call MC.MBoolean. so better you go with the Double brace initialization.
private static final Map<String, Type<?>> types = new HashMap<>() {
{
put(MC.MBoolean.getName(), MC.MBoolean);
put(MC.MInteger.getName(), MC.MInteger);
}
};

how to parametrise the variable in the abstract class

I have the below abstract class where character_1, character_2, character_3 are decleared.
public abstract class Properties {
public static final String character_1 = "//*[#class='character- nav-slide-normal'][#alt='CHARLIE E LOLA']";
public static final String character_2 = "//*[#class='character-nav-slide-normal'][#alt='PEPPA']";
public static final String character_3 = "//*[#class='character-nav-slide-normal'][#alt='FESTA HI-5']";
}
How can I parameterise that and passing through to properties.
String[] myStringArray = {"character_1","character_2","character_3"};
for (int i = 0; i < myStringArray.length; i++)
{
String value = myStringArray[i];
String altvalue = driver.findElement(By.xpath(Properties.value)).getAttribute("alt");
System.out.print(altvalue);
}
I'd say the easiest is to use a HashMap<String, String>.
public class Properties { //no particular use to make this class abstract
public static final Map<String, String> characters;
static
{
characters = new HashMap<String, String>();
characters.put("character_1", "//*[#class='character- nav-slide-normal'][#alt='CHARLIE E LOLA']");
characters.put("character_2", "//*[#class='character-nav-slide-normal'][#alt='PEPPA']");
characters.put("character_3", "//*[#class='character-nav-slide-normal'][#alt='FESTA HI-5']");
}
}
//somewhere else...
String[] myStringArray = {"character_1","character_2","character_3"};
for (String stringArrayString : myStringArray)
{
String xPath = Properties.characters.get(stringArrayString);
String altvalue = driver.findElement(By.xpath(xPath)).getAttribute("alt");
System.out.print(altvalue);
}
You can easily use above code to solve your problem.
However, your quote indicates that you already have something in mind:
I need how to send the value (i.e myStringArray[i] ) to Properties.
???????? so that when i = 0, String altvalue =
driver.findElement(By.xpath(Properties.character_1)).getAttr‌​ibute("alt");
when i=1 , String altvalue =
driver.findElement(By.xpath(Properties.character_2)).getAttr‌​ibute("alt");
like that.
While it is possible with reflection, it is heavily discouraged: you lose compile-time type safety, it causes bugs when refactoring, and performance is slower.
You could use an enum. Something along the lines of
public enum Properties {
CHARACTER_1("//*[#class='character- nav-slide-normal'][#alt='CHARLIE E LOLA']"),
CHARACTER_2("//*[#class='character-nav-slide-normal'][#alt='PEPPA']"),
CHARACTER_3("//*[#class='character-nav-slide-normal'][#alt='FESTA HI-5']"),
CHARACTER_4("//*[#class='character-nav-slide-normal'][#alt='FESTA HI-5']"),
CHARACTER_5("//*[#class='character-nav-slide-normal'][#alt='FESTA HI-5']"),
CHARACTER_6("//*[#class='character-nav-slide-normal'][#alt='FESTA HI-5']"),
CHARACTER_7("//*[#class='character-nav-slide-normal'][#alt='FESTA HI-5']");
private String xpath;
Properties(String xpath) {
this.xpath = xpath;
}
public String getXpath() {
return xpath;
}
}
Example
// Selective properties
Properties[] selectiveProperties = {Properties.CHARACTER_1, Properties.CHARACTER_3, Properties.CHARACTER_6, Properties.CHARACTER_7};
for (Properties property : selectiveProperties) {
String altvalue = driver.findElement(By.xpath(property.getXpath())).getAttribute("alt");
System.out.print(altvalue);
}
//Iterate through all the properties
for (Properties property : Properties.values()) {
String altvalue = driver.findElement(By.xpath(property.getXpath())).getAttribute("alt");
System.out.print(altvalue);
}

read Java public variables as keys from map

I had a static class that contained several static variables:
public class A{
static {
}
public static final String param1= "paramVal1";
public static final String param2= "paramVal2";
}
I want to change the code, so that the variables will be in a map:
public class A{
static {
}
private static Map<String, String> params = new HashMap<String, String>() ;
public static void initParams() {
params.put("param1", paramVal1);
params.put("param2", paramVal2);
}
However, I already have many classes that call those public parameters, and I don't want to go to every class and change it. Is there any way to use some define function, that would cause java to return the map's value, when the parameter is called? i.e if someone calls A.param1, it would return params.get("param1")
A parameter in not as easy to use (and overwrite) than a method. So I think that short answer to your question is no. That's one of the reasons of getters and setters. But you can allways do the inverse, that is keep the old parameters for compatibility and use a map for newer uses :
public class A{
static {
param1 = "paramVal1";
param2 = "paramVal2";
params = new HashMap<String, String>;
params.put("param1", param1);
params.put("param2", param2);
// eventually other inits for params
}
public static final String param1= "paramVal1";
public static final String param2= "paramVal2";
public static Map<String, String params;
/* or better private static Map<String,String> params
and access via getter */
public static getParam(String name) {
return param.get(name);
}
}
That way, old classes could allways do A.param1, and for newer classes you could start using A.get("param1").
You can do this:
public class A {
private static Map<String, String> params = new HashMap<String, String>();
static {
params.put("param1", "paramVal1");
params.put("param2", "paramVal2");
}
public static final String param1 = params.get("param1");
public static final String param2 = params.get("param2");
}

Categories

Resources