Using Java Reflection:
How do I generically access arrays of other objects to retrieve their values ?
Given this Java structure:
class Master
{
static class innerThing
{
static StringBuilder NumOfThings = new StringBuilder( 2);
static class Thing_def
{
static StringBuilder field1 = new StringBuilder( 3);
static StringBuilder field2 = new StringBuilder( 3);
static StringBuilder field3 = new StringBuilder(13);
}
static Thing_def[] Things = new Thing_def [2];
static { for (int i=0; i<Things.length; i++) Things[i] = new Thing_def(); }
}
}
Using Reflection in this bit of code:
Field[] FieldList = DataClass.getDeclaredFields();
if (0 < FieldList.length )
{
SortFieldList( FieldList );
System.out.println();
for (Field eachField : FieldList)
{
String fldType = new String( eachField.getType().toString() );
if ( fldType.startsWith("class [L") )
System.err.printf("\n### fldType= '%s'\n", fldType); //$$$$$$$$$$$$$$$
if ( fldType.startsWith("class java.lang.StringBuilder") )
{
g_iFieldCnt++;
String str = DataClass.getName().replaceAll("\\$",".");
System.out.printf("%s.%s\n", str, eachField.getName() );
}//endif
}//endfor
}//endif
I get the following output:
(Notice that it shows one copy of the fields in Thing_def.)
Master.innerThing.NumOfThings
### fldType= 'class [LMaster$innerThing$Thing_def;'
Master.innerThing.Thing_def.field1
Master.innerThing.Thing_def.field2
Master.innerThing.Thing_def.field3
In another part of the system I access the fields to generate a CSV file:
Field[] FieldList = DataClass.getDeclaredFields();
if (0 < FieldList.length )
{
for (Field eachField : FieldList)
{
String fldType = new String( eachField.getType().toString() );
if ( fldType.startsWith("class java.lang.StringBuilder") )
{
Field fld = DataClass.getDeclaredField( eachField.getName() );
StringBuilder sb = (StringBuilder)fld.get(null);
CSV_file.printf("%s,", sb ); // emit column to CSV
//fld.set( DataClass, new StringBuilder() );
}//endif
}//endfor
}//endif
So in this case I actually will need to directly access array elements.
That is, I need to get at each Master.innerThing.Thing[n].field
So, the big question is:
How do I generically access arrays like this ?
How do I know that Thing_def does not have data,
it is merely a structural definition for Things[ ] ?
Related
So i've been trying to solve this issue for hours but cant seem to find an answer which would work.
i have an object array which stores flight information and i had to remove flights which had Valstybe: "Maldyvai"
so i made a new object array without them, but when i try to print it i get a memory location.
How do i convert the object array to string array?
even though i have a tostring method in my java class
package com.company;
import java.util.*;
import com.company.Isvestine.OroUostasKeleivis;
public class Main {
public static void main(String[] args) {
// write your code here
OroUostasKeleivis Keleiviai1 = new OroUostasKeleivis("Skrydis","Washington","JAV","Tomas","tomaitis","Washington",5465);
OroUostasKeleivis Keleiviai2 = new OroUostasKeleivis("Skrydis","Washington","Maldyvai","Tomas","tomaitis","Maldyvai",5466);
OroUostasKeleivis Keleiviai3 = new OroUostasKeleivis("Skrydis","Washington","JAV","Tomas","tomaitis","Washington",5467);
OroUostasKeleivis Keleiviai4 = new OroUostasKeleivis("Skrydis","Washington","Maldyvai","Tomas","tomaitis","Maldyvai",5468);
OroUostasKeleivis Keleiviai5 = new OroUostasKeleivis("Skrydis","Washington","JAV","Tomas","tomaitis","Washington",5469);
OroUostasKeleivis Keleiviai6 = new OroUostasKeleivis("Skrydis","Washington","Maldyvai","Tomas","tomaitis","Maldyvai",5470);
OroUostasKeleivis Keleiviai7 = new OroUostasKeleivis("Skrydis","Washington","JAV","Tomas","tomaitis","Washington",5475);
OroUostasKeleivis Keleiviai8 = new OroUostasKeleivis("Skrydis","Washington","Maldyvai","Tomas","tomaitis","Maldyvai",5476);
OroUostasKeleivis Keleiviai9 = new OroUostasKeleivis("Skrydis","Washington","JAV","Tomas","tomaitis","Washington",5477);
OroUostasKeleivis Keleiviai10 = new OroUostasKeleivis("Skrydis","Washington","JAV","Tomas","tomaitis","Washington",5488);
OroUostasKeleivis[] keleiviai = new OroUostasKeleivis[10];
keleiviai[0] = Keleiviai1;
keleiviai[1] = Keleiviai2;
keleiviai[2] = Keleiviai3;
keleiviai[3] = Keleiviai4;
keleiviai[4] = Keleiviai5;
keleiviai[5] = Keleiviai6;
keleiviai[6] = Keleiviai7;
keleiviai[7] = Keleiviai8;
keleiviai[8] = Keleiviai9;
keleiviai[9] = Keleiviai10;
for (OroUostasKeleivis keleiveliai:keleiviai) {
System.out.println(keleiveliai);
}
System.out.println("test debug");
OroUostasKeleivis[] keleiviaibemaldyvu = new OroUostasKeleivis[10];
for (int i = 0; i < 10; i++) {
}
System.out.println(IsstrintiMaldyvus(keleiviai));
String convertedStringObject = IsstrintiMaldyvus(keleiviai) .toString();
System.out.println(convertedStringObject );
}
static Object[] IsstrintiMaldyvus(OroUostasKeleivis[] keleiviai){
OroUostasKeleivis[] keleiviaiBeMaldyvu = new OroUostasKeleivis[10];
int pozicija = 0;
for ( OroUostasKeleivis keleiveliai: keleiviai) {
if (keleiveliai.getValstybe() != "Maldyvai"){
keleiviaiBeMaldyvu[pozicija] = keleiveliai;
pozicija++;
}
}
return keleiviaiBeMaldyvu;
}
}
but when i try to print it i get a memory location
Yes, you will NOT have result as you expected, especially calling toString() with any array. See documentation of java.lang.Object.toString() for more details.
So how can we solve problem?
first, override toString() method in OroUostasKeleivis like this:
class OroUostasKeleivis {
#Override
public String toString() {
// your implementation here
return null; // TODO: change here
}
}
Second, you may do either way:
If you're interested in just print out, you can do that with System.out.println(keleiveliai) in for-each loop like you do.
If you're interested in converting OroUostasKeleivis[] to String[], you can:
// this requires Java 8 or later
String[] converted = Arrays.asList(keleiviai)
.stream()
.map(OroUostasKeleivis::toString)
.toArray(String[]::new);
// then use `converted`
Use System.out.println(Arrays.toString(IsstrintiMaldyvus(keleiviai)))
https://www.geeksforgeeks.org/arrays-tostring-in-java-with-examples/
It will print the array contents similar to how ArrayList would get printed if it had the same content.
Think of it as:
[ obj1.toString(), obj2.toString(), ... ]
Using java.util.Arrays#stream(T[]) filter and convert object array to string array and use java.util.Arrays#toString(java.lang.Object[]) convert array to readable string.
final String[] oroUostasKeleivis = Arrays.stream(keleiviai)
.filter(
k -> k.getValStybe() != "Maldyvai"
)
// or other convert code
.map(OroUostasKeleivis::toString)
.toArray(String[]::new);
System.out.println(Arrays.toString(oroUostasKeleivis));
I have a two stack; Stack<String> file and Stack<String[]>author. They have one-to-one relationship, i.e
file author
file1 author3, author2 // file1 is written by author3 and author2
file2 author1, author2 // file2 is written by author1 and author2
I have tried to create new data structure, ( I though Map is best ) to contain all information in pair. For example;
new data structure
author1, file2
author2, file1, file2
author3, file1
To create this pair, I have used HashMap<String, Set<String> allInfo, and implemented the concatanation as;
int len = author.size();
for(int i = 0 ; i <len ; i ++ ){
String []temp = author.pop();
int len2 = temp.length();
for(int j = 0 ; j <len2 ; j ++ ){
if(allInfo.contains(temp[j]) == false){
Set<String> list = new HashSet<String>();
allInfo.put(temp[j], list);
}
Set<String> temp2 = allInfo.get(temp[j]);
temp2.add(file.pop());
}
}
However, it seems this implementation is so ugly. How can I create this pair more cleverly? ( Relying on built-in method of Java is preferred. )
The code below is only a little better. There are (non-JDK) libraries around that provide a data structure called multimap, which is more convenient. But you are stuck with the two stacks, and the inverse ordering of associations, so you'll need a little coding effort.
while( ! author.empty() ){
String f = file.pop(); // Note that in your code this is in the wrong place
for( String aut: author.pop() ){
Set<String> files = allInfo.get( aut );
if( files == null ){
files = new HashSet<>();
allInfo.put( aut, files );
}
files.add( f );
}
}
How about having a custom type for your problem?
public class AuthorPublication{
private String authorName;
private Set<String> files;
//setters and getters
}
What is the best way to treat null values in Java MessageFormat
MessageFormat.format("Value: {0}",null);
=> Value: null
but actually a "Value: " would be nice.
Same with date
MessageFormat.format("Value: {0,date,medium}",null);
=> Value: null
a "Value: " whould be much more appreciated.
Is there any way to do this? I tried choice
{0,choice,null#|notnull#{0,date,dd.MM.yyyy – HH:mm:ss}}
which results in invalid choice format, what is correct to check for "null" or "not null"?
MessageFormat is only null-tolerant; that is, it will handle a null argument. If you want to have a default value appear instead of something if the value you're working with is null, you have two options:
You can either do a ternary...
MessageFormat.format("Value: {0}", null == value ? "" : value));
...or use StringUtils.defaultIfBlank() from commons-lang instead:
MessageFormat.format("Value: {0}", StringUtils.defaultIfBlank(value, ""));
Yes, you cant. Look at javadoc. Unfortunately, it dind't work with NULL.
Try use optional
Optional.ofNullable(value).orElse(0)
Or see example how to use ChoiceFormat and MessageFormat.
For more sophisticated patterns, you can use a ChoiceFormat to produce correct forms for singular and plural:
MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}.");
double[] filelimits = {0,1,2};
String[] filepart = {"no files","one file","{0,number} files"};
ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
form.setFormatByArgumentIndex(0, fileform);
int fileCount = 1273;
String diskName = "MyDisk";
Object[] testArgs = {new Long(fileCount), diskName};
System.out.println(form.format(testArgs));
The output with different values for fileCount:
The disk "MyDisk" contains no files.
The disk "MyDisk" contains one file.
The disk "MyDisk" contains 1,273 files.
You can create the ChoiceFormat programmatically, as in the above example, or by using a pattern. See ChoiceFormat for more information.
form.applyPattern(
"There {0,choice,0#are no files|1#is one file|1
I need that now in my generator class by a mask.
Reason:
User can save mask with multiple types say "{0} {1,number,000} {2,date,MMyyyy}. And user have data where can be nulls. For result i use MessageFormat class. And want empty string without default 'null' text.
Null check is not that easy, because it will means replace pattern that is used for many records (not just one). And default empty value don't exists for number or date.
So if someone still needs solution. I give my.
Add this methods/classes (I have all in one class)
private static Object[] replaceNulls2NullValues( Object[] values ) {
for ( int i = 0; i < values.length; i++ )
if ( values[i] == null )
values[i] = NullFormatValue.NULL_FORMAT_VALUE;
return values;
}
private static MessageFormat modifyFormaterFormats( MessageFormat formater ) {
formater.setFormats( Arrays.stream( formater.getFormats() ).map( ( f ) -> ( f != null ) ? new NullHandlingFormatWrapper( f ) : null ).toArray( ( l ) -> new Format[l] ) );
return formater;
}
private static final class NullFormatValue {
static final Object NULL_FORMAT_VALUE = new NullFormatValue();
private NullFormatValue() {
}
#Override
public String toString() {
return "";
}
}
private static class NullHandlingFormatWrapper extends Format {
protected Format wrappedFormat;
public NullHandlingFormatWrapper( Format format ) {
wrappedFormat = format;
}
#Override
public StringBuffer format( Object obj, StringBuffer toAppendTo, FieldPosition pos ) {
if ( !( obj instanceof NullFormatValue ) )
wrappedFormat.format( obj, toAppendTo, pos );
return toAppendTo;
}
#Override
public Object parseObject( String source, ParsePosition pos ) {
return wrappedFormat.parseObject( source, pos );
}
}
and for result call
modifyFormaterFormats( new MessageFormat( pattern ) ).format( replaceNulls2NullValues( parameters ) );
I've an ExcelReader class which reads from Excel and populates the appropriate lists.
public static List<Address> addressList;
public static List<User> userList;
Above lists are being populated like this by the ExcelReader:
addressList = new ArrayList<Address>();
Address a = new Address();
a.setAddress1(r.getCell(0).getStringCellValue());
a.setCity(r.getCell(1).getStringCellValue());
I want to use this data in my Selenium test cases. I was planning to use TestNG's #DataProvider tag to feed the test case, but it only accepts Object[][] and Iterator.
Is there a way to convert these lists into an Object[][] format?
I am also open to any suggestions if you prefer to use anything other than #DataProvider.
Thanks in advance
There are lots of ways to do this, but here is an idea. I wrote an example here that does it.
The general gist of the idea is, using the MetaModel api:
public static Object[][] get2ArgArrayFromRows( List<Row> rows ) {
Object[][] myArray = new Object[rows.size()][2];
int i = 0;
SelectItem[] cols = rows.get(0).getSelectItems();
for ( Row r : rows ) {
Object[] data = r.getValues();
for ( int j = 0; j < cols.length; j++ ) {
if ( data[j] == null ) data[j] = ""; // force empty string where there are NULL values
}
myArray[i][0] = cols;
myArray[i][1] = data;
i++;
}
logger.info( "Row count: " + rows.size() );
logger.info( "Column names: " + Arrays.toString( cols ) );
return myArray;
}
public static Object[][] getCsvData( File csvFile )
{
CsvConfiguration conf = new CsvConfiguration( 1 );
DataContext csvContext = DataContextFactory.createCsvDataContext( csvFile, conf );
Schema schema = csvContext.getDefaultSchema();
Table[] tables = schema.getTables();
Table table = tables[0]; // a representation of the csv file name including extension
DataSet dataSet = csvContext.query()
.from( table )
.selectAll()
.where("run").eq("Y")
.execute();
List<Row> rows = dataSet.toRows();
Object[][] myArray = get2ArgArrayFromRows( rows );
return myArray;
}
Now, this code above is just a ROUGH idea. What you really need to do is merge cols and data into a Map<String,String> object and then pass that as the first argument back to your test, containing all parameters from the CSV file, including browser type. Then, as the second argument, set it like so:
myArray[i][1] = new WebDriverBuilderHelper();
Then, in your #Test annotated method, instantiate the driver:
#Test(dataProvider = "dp")
public void testIt( Map<String,String> map, WebDriverBuilderHelper wdhelper ) {
wdhelper.instantiateBrowser( map.get("browser") );
wdhelper.navigateTo(url);
....
I am using the String split method and I want to have the last element.
The size of the Array can change.
Example:
String one = "Düsseldorf - Zentrum - Günnewig Uebachs"
String two = "Düsseldorf - Madison"
I want to split the above Strings and get the last item:
lastone = one.split("-")[here the last item] // <- how?
lasttwo = two.split("-")[here the last item] // <- how?
I don't know the sizes of the arrays at runtime :(
You could use lastIndexOf() method on String
String last = string.substring(string.lastIndexOf('-') + 1);
Save the array in a local variable and use the array's length field to find its length. Subtract one to account for it being 0-based:
String[] bits = one.split("-");
String lastOne = bits[bits.length-1];
Caveat emptor: if the original string is composed of only the separator, for example "-" or "---", bits.length will be 0 and this will throw an ArrayIndexOutOfBoundsException. Example: https://onlinegdb.com/r1M-TJkZ8
You can use the StringUtils class in Apache Commons:
StringUtils.substringAfterLast(one, "-");
using a simple, yet generic, helper method like this:
public static <T> T last(T[] array) {
return array[array.length - 1];
}
you can rewrite:
lastone = one.split("-")[..];
as:
lastone = last(one.split("-"));
String str = "www.anywebsite.com/folder/subfolder/directory";
int index = str.lastIndexOf('/');
String lastString = str.substring(index +1);
Now lastString has the value "directory"
Gathered all possible ways together!!
By using lastIndexOf() & substring() methods of Java.lang.String
// int firstIndex = str.indexOf( separator );
int lastIndexOf = str.lastIndexOf( separator );
String begningPortion = str.substring( 0, lastIndexOf );
String endPortion = str.substring( lastIndexOf + 1 );
System.out.println("First Portion : " + begningPortion );
System.out.println("Last Portion : " + endPortion );
split()Java SE 1.4. Splits the provided text into an array.
String[] split = str.split( Pattern.quote( separator ) );
String lastOne = split[split.length-1];
System.out.println("Split Array : "+ lastOne);
How to split String before first comma?
Java 8 sequential ordered stream from an array.
String firstItem = Stream.of( split )
.reduce( (first,last) -> first ).get();
String lastItem = Stream.of( split )
.reduce( (first,last) -> last ).get();
System.out.println("First Item : "+ firstItem);
System.out.println("Last Item : "+ lastItem);
Apache Commons Langjar « org.apache.commons.lang3.StringUtils
String afterLast = StringUtils.substringAfterLast(str, separator);
System.out.println("StringUtils AfterLast : "+ afterLast);
String beforeLast = StringUtils.substringBeforeLast(str, separator);
System.out.println("StringUtils BeforeLast : "+ beforeLast);
String open = "[", close = "]";
String[] groups = StringUtils.substringsBetween("Yash[777]Sam[7]", open, close);
System.out.println("String that is nested in between two Strings "+ groups[0]);
Guava: Google Core Libraries for Java. « com.google.common.base.Splitter
Splitter splitter = Splitter.on( separator ).trimResults();
Iterable<String> iterable = splitter.split( str );
String first_Iterable = Iterables.getFirst(iterable, "");
String last_Iterable = Iterables.getLast( iterable );
System.out.println(" Guava FirstElement : "+ first_Iterable);
System.out.println(" Guava LastElement : "+ last_Iterable);
Scripting for the Java Platform « Run Javascript on the JVM with Rhino/Nashorn
Rhino « Rhino is an open-source implementation of JavaScript written entirely in Java. It is typically embedded into Java applications to provide scripting to end users. It is embedded in J2SE 6 as the default Java scripting engine.
Nashorn is a JavaScript engine developed in the Java programming language by Oracle. It is based on the Da Vinci Machine and has been released with Java 8.
Java Scripting Programmer's Guide
public class SplitOperations {
public static void main(String[] args) {
String str = "my.file.png.jpeg", separator = ".";
javascript_Split(str, separator);
}
public static void javascript_Split( String str, String separator ) {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
// Script Variables « expose java objects as variable to script.
engine.put("strJS", str);
// JavaScript code from file
File file = new File("E:/StringSplit.js");
// expose File object as variable to script
engine.put("file", file);
try {
engine.eval("print('Script Variables « expose java objects as variable to script.', strJS)");
// javax.script.Invocable is an optional interface.
Invocable inv = (Invocable) engine;
// JavaScript code in a String
String functions = "function functionName( functionParam ) { print('Hello, ' + functionParam); }";
engine.eval(functions);
// invoke the global function named "functionName"
inv.invokeFunction("functionName", "function Param value!!" );
// evaluate a script string. The script accesses "file" variable and calls method on it
engine.eval("print(file.getAbsolutePath())");
// evaluate JavaScript code from given file - specified by first argument
engine.eval( new java.io.FileReader( file ) );
String[] typedArray = (String[]) inv.invokeFunction("splitasJavaArray", str );
System.out.println("File : Function returns an array : "+ typedArray[1] );
ScriptObjectMirror scriptObject = (ScriptObjectMirror) inv.invokeFunction("splitasJavaScriptArray", str, separator );
System.out.println("File : Function return script obj : "+ convert( scriptObject ) );
Object eval = engine.eval("(function() {return ['a', 'b'];})()");
Object result = convert(eval);
System.out.println("Result: {}"+ result);
// JavaScript code in a String. This code defines a script object 'obj' with one method called 'hello'.
String objectFunction = "var obj = new Object(); obj.hello = function(name) { print('Hello, ' + name); }";
engine.eval(objectFunction);
// get script object on which we want to call the method
Object object = engine.get("obj");
inv.invokeMethod(object, "hello", "Yash !!" );
Object fileObjectFunction = engine.get("objfile");
inv.invokeMethod(fileObjectFunction, "hello", "Yashwanth !!" );
} catch (ScriptException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static Object convert(final Object obj) {
System.out.println("\tJAVASCRIPT OBJECT: {}"+ obj.getClass());
if (obj instanceof Bindings) {
try {
final Class<?> cls = Class.forName("jdk.nashorn.api.scripting.ScriptObjectMirror");
System.out.println("\tNashorn detected");
if (cls.isAssignableFrom(obj.getClass())) {
final Method isArray = cls.getMethod("isArray");
final Object result = isArray.invoke(obj);
if (result != null && result.equals(true)) {
final Method values = cls.getMethod("values");
final Object vals = values.invoke(obj);
System.err.println( vals );
if (vals instanceof Collection<?>) {
final Collection<?> coll = (Collection<?>) vals;
Object[] array = coll.toArray(new Object[0]);
return array;
}
}
}
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException
| IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
}
}
if (obj instanceof List<?>) {
final List<?> list = (List<?>) obj;
Object[] array = list.toArray(new Object[0]);
return array;
}
return obj;
}
}
JavaScript file « StringSplit.js
// var str = 'angular.1.5.6.js', separator = ".";
function splitasJavaArray( str ) {
var result = str.replace(/\.([^.]+)$/, ':$1').split(':');
print('Regex Split : ', result);
var JavaArray = Java.to(result, "java.lang.String[]");
return JavaArray;
// return result;
}
function splitasJavaScriptArray( str, separator) {
var arr = str.split( separator ); // Split the string using dot as separator
var lastVal = arr.pop(); // remove from the end
var firstVal = arr.shift(); // remove from the front
var middleVal = arr.join( separator ); // Re-join the remaining substrings
var mainArr = new Array();
mainArr.push( firstVal ); // add to the end
mainArr.push( middleVal );
mainArr.push( lastVal );
return mainArr;
}
var objfile = new Object();
objfile.hello = function(name) { print('File : Hello, ' + name); }
JavaScript Array constructor or array literal.
With Guava:
final Splitter splitter = Splitter.on("-").trimResults();
assertEquals("Günnewig Uebachs", Iterables.getLast(splitter.split(one)));
assertEquals("Madison", Iterables.getLast(splitter.split(two)));
Splitter, Iterables
Since he was asking to do it all in the same line using split so i suggest this:
lastone = one.split("-")[(one.split("-")).length -1]
I always avoid defining new variables as far as I can, and I find it a very good practice
You mean you don't know the sizes of the arrays at compile-time? At run-time they could be found by the value of lastone.length and lastwo.length .
Also you can use java.util.ArrayDeque
String last = new ArrayDeque<>(Arrays.asList("1-2".split("-"))).getLast();
In java 8
String lastItem = Stream.of(str.split("-")).reduce((first,last)->last).get();
I guess you want to do this in i line. It is possible (a bit of juggling though =^)
new StringBuilder(new StringBuilder("Düsseldorf - Zentrum - Günnewig Uebachs").reverse().toString().split(" - ")[0]).reverse()
tadaa, one line -> the result you want (if you split on " - " (space minus space) instead of only "-" (minus) you will loose the annoying space before the partition too =^) so "Günnewig Uebachs" instead of " Günnewig Uebachs" (with a space as first character)
Nice extra -> no need for extra JAR files in the lib folder so you can keep your application light weight.