I am trying to solve this problem for an UDF I am creating for hiveql environment.
public ObjectInspector initialize(ObjectInspector[] arguments)
throws UDFArgumentException {
if (arguments.length != 1) {
throw new UDFArgumentException("Usage : multiple_prop(primitive var) ");
}
// This will be an string
moi = (PrimitiveObjectInspector) arguments[0];
ArrayList structFieldNames = new ArrayList();
ArrayList structFieldObjectInspectors = new ArrayList();
structFieldNames.add("fields name"); <-- Issue is here
How could I do to get the field name in there? It can be easily done for structObjectInspectors, but how do we manage this in PrimitiveObjectInspectors?
Complete code would be this one
public class prop_step2 extends GenericUDF {
private PrimitiveObjectInspector moi;
#Override
public ObjectInspector initialize(ObjectInspector[] arguments)
throws UDFArgumentException {
if (arguments.length != 1) {
throw new UDFArgumentException("Usage : multiple_prop(primitive var) ");
}
// This will be an string
moi = (PrimitiveObjectInspector) arguments[0];
ArrayList structFieldNames = new ArrayList();
ArrayList structFieldObjectInspectors = new ArrayList();
// Change this to get the input variable name, and not the type name
structFieldNames.add(moi.getTypeName());<-- Change this to field name
structFieldObjectInspectors.add( PrimitiveObjectInspectorFactory.writableStringObjectInspector );
return ObjectInspectorFactory.getStandardStructObjectInspector(structFieldNames, structFieldObjectInspectors);
}
#Override
public Object evaluate(DeferredObject[] arguments) throws HiveException {
Object[] result;
result = new Object[1];
Text elem1 = new Text((String) moi.getPrimitiveJavaObject(arguments[0].get()));
result[0]= elem1;
return result;
}
#Override
public String getDisplayString(String[] children) {
return "stop";
}}
When this would be finished, i would like to call this udf from hive:
CREATE TEMPORARY FUNCTION step AS 'UDFpack.prop_step2';
select
step(bit) as sd
from my_table
And i would expect that if in an upper select i did this : sd.bit i would obtain the value of 'bit'.
It's simply not possible. The information passed to the UDF - the ObjectInspectors - do not contain their name. That's why you can see the output column names being changed to _col0, _col1 .. in the intermediary stages of a Hive explain plan. I am also quite annoyed by this and think this is an oversight by Hive.
A workaround would be to put your input into a struct and parse that.
i.e step(named_struct('bit',bit)) and then you can get the field name of the struct in your UDF. But it's not nearly as nice
Below is my code and the print method is in the first class (Hyrestagare) as "public String address()".
I keep reading similar questions and answers in Stackoverflow. But I just get more confused. I make changes to the code, rewrite parts, but just can't solve the problem. :(
First of all, I would not recommend returning null ever, it just makes dealing with NullPointerExceptions even harder.
regarding your problem:
public String address(){
for (Hus h : houses){
return h.getAddress();
}
return null;
}
The problem here is in your example above, you create an instance of Hyrestagare called a1 but you never add any houses to this class.
Thats why when you later call a1.address(), your array of houses is empty, so it just returns null;.
As you use an ArrayListof Hus you will have multiple addresses. The problem with your approach, you will only get the element of the first address, because you return (escape out of the functions) the value.
Depending on what your goal with this function is, i could offer you some solutions:
1) This would return all addresses as a new list. If there where no addresses, than you will get an empty list and don't have to deal with null.
public List<String> getAddresses(List<Hus> list){
return list.stream()
.map(Hus::getAddress)
.collect(Collectors.toList());
}
If this solution is to complex for you, this gives you the same result with simpler code:
public List<String> getAddresses(List<Hus> list){
List<String> addresses = new ArrayList<>();
for(Hus h: list){
addresses.add(h.getAddress());
}
return addresses;
}
But if you just want the first address, like in your code (If intended or not):
public static String getAddress(List<Hus> list){
if(list.isEmpty()){
return "no address";
} else {
return list.get(0).getAddress();
}
}
In Hyrestagare class, address() method calls getAddress() on Hus object, however, there is no setAddress() call in Demo class and hence, address remains null, try the following:
Hyrestagare a1 = new Hyrestagare();
a1.setNamn("Donald");
a1.setPersonnummer(111);
Hyrestagare a2 = new Hyrestagare();
a2.setNamn("Ivanka");
a2.setPersonnummer(222);
Hyrestagare b1 = new Hyrestagare();
b1.setNamn("Barack");
b1.setPersonnummer(333);
Hyrestagare b2 = new Hyrestagare();
b2.setNamn("Michelle");
b2.setPersonnummer(444);
Lagenhet l1 = new Lagenhet();
l1.setHyra(5000);
l1.setNummer(1);
l1.setYta(200);
Lagenhet l2 = new Lagenhet();
l2.setHyra(2000);
l2.setNummer(2);
l2.setYta(50);
Hus hus1 = new Hus();
hus1.setAddress("Test Address");//sets the address
// HYRESTAGARE KOPPLA TILL LAGENHET
a1.setLagenhet(l1);
a2.setLagenhet(l1);
b1.setLagenhet(l2);
b2.setLagenhet(l2);
// LAGENHET KOPPLA HYRESTAGARE TILL LAGENHET, KOPPLA LISTA TILL LAGENHET
ArrayList<Hyrestagare> renters = new ArrayList<Hyrestagare>();
l1.laggTillHyrestagare(a1);
l1.laggTillHyrestagare(a2);
l2.laggTillHyrestagare(b1);
l2.laggTillHyrestagare(b2);
l1.setRenter(renters);
l2.setRenter(renters);
renters.add(a1);
renters.add(a2);
renters.add(b1);
renters.add(b2);
// HUS KOPPLA LAGENHET TILL LISTA
ArrayList<Lagenhet> flats = new ArrayList<Lagenhet>();
hus1.laggTillLagenhet(l1);
hus1.laggTillLagenhet(l2);
hus1.setApartments(flats);
flats.add(l1);
flats.add(l2);
// KOPPLA HUS TILL HUS LISTA
ArrayList<Hus> buildings = new ArrayList<Hus>();
buildings.add(hus1);
// PRINT METODER
for (Hyrestagare temp : hus1.printHyrestagare(1)){
System.out.println("Hyrestagare: " + temp.getNamn() + " (" + temp.getPersonnummer() + ").");
}
for (Hyrestagare temp : hus1.printHyrestagare(2)){
System.out.println("Hyrestagare: " + temp.getNamn() + " (" + temp.getPersonnummer() + ").");
}
System.out.println("Address: " + a1.address());
I have created an AsynTaskInsideActivity class that extends AsyncTask<Void, Void, List<String>> within the MainActivity as an inner class. I am using this AsynTaskInsideActivity for getting all the records from the location table. This location table has following columns:
location_id
country
state
zip_code
And I want to fetch records from each individual column. So, for storing every record of each individual column I created four List type arrays (i.e. one for each column) and successfully stored the retrieved Cursor data within each of them. Now, the problem is I need to return every column's records. So, to be specific how can I return those four individual List type arrays from a one AsyncTask class. Currently, I am returning only the list type array namely locationId which has all the location ids I fetched from location table's location_id column.
Questions:
How can I return multiple list array items from a single AsyncTask class? After all when we query a database, sometimes we need records from multiple columns from an individual table to process further operations.
Is there any better approach that I can use to overcome this problem? or I have to believe some things are really impossible.
This is what my AsyncTask class looks like:
public class AsyncTaskInsideActivity extends AsyncTask<Void, Void, List<String>> {
private static final String CLASS_TAG = AsyncTaskInsideActivity.class.getSimpleName();
#Override
protected List<String> doInBackground(Void... params) {
Log.v(CLASS_TAG, "AsyncTaskInsideActivity started successfully....");
SoCalledDbHelper soCalledDbHelper = new SoCalledDbHelper
(getBaseContext());
//key-value pairs for inserting data into the table
ContentValues soCalledValues = new ContentValues();
soCalledValues.put(SoCalledContract.LocationTable.COLUMN_CITY_NAME, "Kim Kardishian");
soCalledValues.put(SoCalledContract.LocationTable.COLUMN_STATE, "No Ass Holes");
soCalledValues.put(SoCalledContract.LocationTable.COLUMN_ZIP_CODE, 007);
//insert location data
soCalledDbHelper.addLocationData(soCalledValues);
//For storing the cursor data which will be retrieved by the read query.
Cursor locationDataCursor;
//Query for all the data in the location table
locationDataCursor = soCalledDbHelper.getAllLocationData(null, null, null, null);
List<String> sCLocationId = new ArrayList<String>();
List<String> sCCityName = new ArrayList<String>();
List<String> sCState = new ArrayList<String>();
List<String> sCZipCode = new ArrayList<String>();
if (locationDataCursor.getCount() > 0) {
//Reset the cursor location
locationDataCursor.moveToPosition(-1);
while (locationDataCursor.moveToNext()) {
//Extracting data from the location cursor
sCLocationId.add(locationDataCursor.getString
(locationDataCursor.getColumnIndex("_id")));
sCCityName.add(locationDataCursor.getString
(locationDataCursor.getColumnIndex("city_name")));
sCState.add(locationDataCursor.getString
(locationDataCursor.getColumnIndex("state")));
sCZipCode.add(locationDataCursor.getString
(locationDataCursor.getColumnIndex("zip_code")));
}
Log.i(CLASS_TAG, "Success: Cursor has data! #Total Records: " +
locationDataCursor.getCount());
for (String locationIds : sCLocationId) {
Log.i(CLASS_TAG, "Location Id: + " + locationIds);
}
for (String cityNamez : sCCityName) {
Log.i(CLASS_TAG, "City Names: + " + cityNamez);
}
for (String statesNames : sCState) {
Log.i(CLASS_TAG, "State Names: + " + statesNames);
}
for (String zipCodes : sCZipCode) {
Log.i(CLASS_TAG, "Zip Codes: + " + zipCodes);
}
} else {
Log.w(CLASS_TAG, "Error: Cursor is empty! #Total Records: " +
locationDataCursor.getCount());
}
locationDataCursor.close();
soCalledDbHelper.close();
Log.v(CLASS_TAG, "AsyncTaskDbHelper ended successfully....");
return sCLocationId;
}
}
You could just return extend your AsyncTask off of AsyncTask<Void, Void, List<List<String>> and be done with it but this is not the best approach.
A better approach would be to extend off of AsyncTask<Void, Void, List<Location>> where Location is defined as:
public class Location
{
private String location_id;
private String country;
private String state;
private String zip_code;
// Constructors, getters and setters go here. Your IDE should be able to generate them.
// You can also override the toString method to format the output better
}
Your loop would then look something like this:
List<Location> locations_list = new ArrayList<Location>();
if (locationDataCursor.moveToFirst()) {// Moves to first if cursor is not empty
do{
Location location = new Location();
//Extracting data from the location cursor
location.setID(locationDataCursor.getString
(locationDataCursor.getColumnIndex("_id")));
location.setCity(locationDataCursor.getString
(locationDataCursor.getColumnIndex("city_name")));
location.setState(locationDataCursor.getString
(locationDataCursor.getColumnIndex("state")));
location.setZip(locationDataCursor.getString
(locationDataCursor.getColumnIndex("zip_code")));
// Add location to the list
locations_list.add(location)
}while (locationDataCursor.moveToNext())
Log.i(CLASS_TAG, "Success: Cursor has data! #Total Records: " +
locationDataCursor.getCount());
for (Location l : locations_list) {
Log.i(CLASS_TAG, "Location: " + l.toString());
}
} else {
Log.w(CLASS_TAG, "Error: Cursor is empty!"
}
// Close any open DB objects
locationDataCursor.close();
soCalledDbHelper.close();
Log.v(CLASS_TAG, "AsyncTaskDbHelper ended successfully....");
// Return the list of locations
return locations_list;
Well, after researching for the solution to this question over the internet and devoting several hours for getting the single AsyncTask to return multiple values I came up with a solution with a nested List array i.e. List<List<String>>
Original Credits:
#Simon: Who gave me an indication (or hint) that how could I update my AsyncTask to get the job done, that was proved to be really helpful.
#VERT9x: Thanks for putting the effort and getting the job done with a different approach.
Solution:
public class AsyncTaskInsideActivity extends AsyncTask<Void, Void, List<List<String>>> {
private static final String CLASS_TAG = AsyncTaskInsideActivity.class.getSimpleName();
#Override
protected List<String> doInBackground(Void... params) {
Log.v(CLASS_TAG, "AsyncTaskInsideActivity started successfully....");
SoCalledDbHelper soCalledDbHelper = new SoCalledDbHelper
(getBaseContext());
//key-value pairs for inserting data into the table
ContentValues soCalledValues = new ContentValues();
soCalledValues.put(SoCalledContract.LocationTable.COLUMN_CITY_NAME, "Kim Kardishian");
soCalledValues.put(SoCalledContract.LocationTable.COLUMN_STATE, "No Ass Holes");
soCalledValues.put(SoCalledContract.LocationTable.COLUMN_ZIP_CODE, 007);
//insert location data
soCalledDbHelper.addLocationData(soCalledValues);
//For storing the cursor data which will be retrieved by the read query.
Cursor locationDataCursor;
//Query for all the data in the location table
locationDataCursor = soCalledDbHelper.getAllLocationData(null, null, null, null);
List<String> sCLocationId = new ArrayList<String>();
List<String> sCCityName = new ArrayList<String>();
List<String> sCState = new ArrayList<String>();
List<String> sCZipCode = new ArrayList<String>();
if (locationDataCursor.getCount() > 0) {
//Reset the cursor location
locationDataCursor.moveToPosition(-1);
while (locationDataCursor.moveToNext()) {
//Extracting data from the location cursor
sCLocationId.add(locationDataCursor.getString
(locationDataCursor.getColumnIndex("_id")));
sCCityName.add(locationDataCursor.getString
(locationDataCursor.getColumnIndex("city_name")));
sCState.add(locationDataCursor.getString
(locationDataCursor.getColumnIndex("state")));
sCZipCode.add(locationDataCursor.getString
(locationDataCursor.getColumnIndex("zip_code")));
}
Log.i(CLASS_TAG, "Success: Cursor has data! #Total Records: " +
locationDataCursor.getCount());
for (String locationIds : sCLocationId) {
Log.i(CLASS_TAG, "Location Id: + " + locationIds);
}
for (String cityNamez : sCCityName) {
Log.i(CLASS_TAG, "City Names: + " + cityNamez);
}
for (String statesNames : sCState) {
Log.i(CLASS_TAG, "State Names: + " + statesNames);
}
for (String zipCodes : sCZipCode) {
Log.i(CLASS_TAG, "Zip Codes: + " + zipCodes);
}
} else {
Log.w(CLASS_TAG, "Error: Cursor is empty! #Total Records: " +
locationDataCursor.getCount());
}
locationDataCursor.close();
soCalledDbHelper.close();
//Creating a List that can store List(s) within it.
//List of Lists String
List<List<String>> arrayOfLists = new ArrayList<List<String>>();
//Adding those Lists that was used to store each column records
arrayOfLists.add(sCLocationId);
arrayOfLists.add(sCCityName);
arrayOfLists.add(sCState);
arrayOfLists.add(sCZipCode);
//Start iterating over the parent arrayOfLists List
for(int i = 0; i < arrayOfLists.size(); i++) {
//Print each arrayOfLists data item it contains
Log.v(CLASS_TAG, "Parent List: " + arrayOfLists.get(i).toString());
//Start iterating over child of arrayOfLists List
for(int j = 0; j < arrayOfLists.get(i).size(); j++) {
//Print each arrayOfLists CHILD data item it contains
Log.v(CLASS_TAG, "Child List: " + arrayOfLists.get(i).get(j).toString());
}
}
//Size of the arrayOfLists
Log.v(CLASS_TAG, "Parent List Size: " + Integer.toString(arrayOfLists.size()));
//Size of the arrayOfLists child container
Log.v(CLASS_TAG, "Child List Size: " + Integer.toString(arrayOfLists.get(1).size()));
Log.v(CLASS_TAG, "AsyncTaskDbHelper ended successfully....");
return arrayOfLists;
}
Changes I Made:
Changed the 3rd parameter of AsyncTask class and doInBackground() return type to List<List<String>>, so it can return multiple values.
For solution see under these two lines:
locationDataCursor.close();
soCalledHelper.close();
I'm hoping to trim all Strings that are part of an object graph.
So I have an object graph like so
RootElement
- name (String)
- adjective (String)
- items ArrayOfItems
- getItems (List<Item>)
- get(i) (Item)
Item
- name (String)
- value (double)
- alias (String)
- references ArrayOfReferences
- getReferences (List<Reference>)
- get(i) (Reference)
Reference
- prop1 (String)
- prop2 (Integer)
- prop3 (String)
There is a get and set pair for every property of every class represented in this object graph. Ideally every field of type String would end up trimmed, including enumerating any child objects contained in collections. There are no cycles contained within the object graph.
Is there any java library that implements some sort of generic object graph visitor pattern or String\Reflection utility library that does this?
An external third party library that does this would also be fine, it does not have to be part of the standard java libraries.
No, there's no built-in traversal for something like this, and remember that Java Strings are immutable, so you can't actually trim in place--you have to trim and replace. Some objects may not permit modification of their String variables.
Below is the explanation of solution that I have built using Java Reflection API. I have posted the working code (with its url to github) below. This solution mainly uses:
Java Reflection API
Independent handling of Java Collections
Recursion
To start with, I have used Introspector to go over the readMethods of the Class omitting the methods defined for Object
for (PropertyDescriptor propertyDescriptor : Introspector
.getBeanInfo(c, Object.class).getPropertyDescriptors()) {
Method method = propertyDescriptor.getReadMethod();
Cases
If the current level of Property is of type String
If its an Object Array of Properties
If its a String array
If its a type of Java Collection class
Separate placement for Map with special conditions to process its keys and values
This utility uses the Java Reflection API to traverse through an object graph with disciplined syntax of getters and setters and trims all strings encountered within an Object graph recursively.
Code
This entire util class with the main test class (and custom data types/pojos) is here on my github
Usage:
myObj = (MyObject) SpaceUtil.trimReflective(myObj);
Util method:
public static Object trimReflective(Object object) throws Exception {
if (object == null)
return null;
Class<? extends Object> c = object.getClass();
try {
// Introspector usage to pick the getters conveniently thereby
// excluding the Object getters
for (PropertyDescriptor propertyDescriptor : Introspector
.getBeanInfo(c, Object.class).getPropertyDescriptors()) {
Method method = propertyDescriptor.getReadMethod();
String name = method.getName();
// If the current level of Property is of type String
if (method.getReturnType().equals(String.class)) {
String property = (String) method.invoke(object);
if (property != null) {
Method setter = c.getMethod("set" + name.substring(3),
new Class<?>[] { String.class });
if (setter != null)
// Setter to trim and set the trimmed String value
setter.invoke(object, property.trim());
}
}
// If an Object Array of Properties - added additional check to
// avoid getBytes returning a byte[] and process
if (method.getReturnType().isArray()
&& !method.getReturnType().isPrimitive()
&& !method.getReturnType().equals(String[].class)
&& !method.getReturnType().equals(byte[].class)) {
System.out.println(method.getReturnType());
// Type check for primitive arrays (would fail typecasting
// in case of int[], char[] etc)
if (method.invoke(object) instanceof Object[]) {
Object[] objectArray = (Object[]) method.invoke(object);
if (objectArray != null) {
for (Object obj : (Object[]) objectArray) {
// Recursively revisit with the current property
trimReflective(obj);
}
}
}
}
// If a String array
if (method.getReturnType().equals(String[].class)) {
String[] propertyArray = (String[]) method.invoke(object);
if (propertyArray != null) {
Method setter = c.getMethod("set" + name.substring(3),
new Class<?>[] { String[].class });
if (setter != null) {
String[] modifiedArray = new String[propertyArray.length];
for (int i = 0; i < propertyArray.length; i++)
if (propertyArray[i] != null)
modifiedArray[i] = propertyArray[i].trim();
// Explicit wrapping
setter.invoke(object,
new Object[] { modifiedArray });
}
}
}
// Collections start
if (Collection.class.isAssignableFrom(method.getReturnType())) {
Collection collectionProperty = (Collection) method
.invoke(object);
if (collectionProperty != null) {
for (int index = 0; index < collectionProperty.size(); index++) {
if (collectionProperty.toArray()[index] instanceof String) {
String element = (String) collectionProperty
.toArray()[index];
if (element != null) {
// Check if List was created with
// Arrays.asList (non-resizable Array)
if (collectionProperty instanceof List) {
((List) collectionProperty).set(index,
element.trim());
} else {
collectionProperty.remove(element);
collectionProperty.add(element.trim());
}
}
} else {
// Recursively revisit with the current property
trimReflective(collectionProperty.toArray()[index]);
}
}
}
}
// Separate placement for Map with special conditions to process
// keys and values
if (method.getReturnType().equals(Map.class)) {
Map mapProperty = (Map) method.invoke(object);
if (mapProperty != null) {
// Keys
for (int index = 0; index < mapProperty.keySet().size(); index++) {
if (mapProperty.keySet().toArray()[index] instanceof String) {
String element = (String) mapProperty.keySet()
.toArray()[index];
if (element != null) {
mapProperty.put(element.trim(),
mapProperty.get(element));
mapProperty.remove(element);
}
} else {
// Recursively revisit with the current property
trimReflective(mapProperty.get(index));
}
}
// Values
for (Map.Entry entry : (Set<Map.Entry>) mapProperty
.entrySet()) {
if (entry.getValue() instanceof String) {
String element = (String) entry.getValue();
if (element != null) {
entry.setValue(element.trim());
}
} else {
// Recursively revisit with the current property
trimReflective(entry.getValue());
}
}
}
} else {// Catch a custom data type as property and send through
// recursion
Object property = (Object) method.invoke(object);
if (property != null) {
trimReflective(property);
}
}
}
} catch (Exception e) {
throw new Exception("Strings cannot be trimmed because: ", e);
}
return object;
}
Test
I also have a test class in there which creates a relatively complex object. The test class has different scenarios that cover:
String properties
Properties as custom datatypes which in turn have String properties
Properties as custom datatypes which in turn have properties as custom datatypes which in turn have String properties
List of custom data types
Set of Strings
Array of custom data types
Array of Strings
Map of String and custom data type
Object Graph:
Test Object Code Snippet:
public static Music buildObj() {
Song song1 = new Song();
Song song2 = new Song();
Song song3 = new Song();
Artist artist1 = new Artist();
Artist artist2 = new Artist();
song1.setGenre("ROCK ");
song1.setSonnet("X ");
song1.setNotes("Y ");
song1.setCompostions(Arrays.asList(new String[] { "SOME X DATA ",
"SOME OTHER DATA X ", "SOME MORE DATA X ", " " }));
Set<String> instruments = new HashSet<String>();
instruments.add(" GUITAR ");
instruments.add(" SITAR ");
instruments.add(" DRUMS ");
instruments.add(" BASS ");
song1.setInstruments(instruments);
song2.setGenre("METAL ");
song2.setSonnet("A ");
song2.setNotes("B ");
song2.setCompostions(Arrays.asList(new String[] { "SOME Y DATA ",
" SOME OTHER DATA Y ",
" SOME MORE DATA Y ", " " }));
song3.setGenre("POP ");
song3.setSonnet("DONT ");
song3.setNotes("KNOW ");
song3.setCompostions(Arrays.asList(new String[] { "SOME Z DATA ",
" SOME OTHER DATA Z ",
" SOME MORE DATA Z ", " " }));
artist1.setSongList(Arrays.asList(new Song[] { song1, song3 }));
artist2.setSongList(Arrays.asList(new Song[] { song1, song2, song3 }));
Map<String, Person> artistMap = new HashMap<String, Person>();
Person tutor1 = new Person();
tutor1.setName("JOHN JACKSON DOE ");
artistMap.put(" Name ", tutor1);
Person coach1 = new Person();
coach1.setName("CARTER ");
artistMap.put("Coach ", coach1);
artist2.setTutor(artistMap);
music.setSongs(Arrays.asList(new Song[] { song1, song2, song3 }));
music.setArtists(Arrays.asList(new Artist[] { artist1, artist2 }));
music.setLanguages(new String[] { " ENGLISH ", "FRENCH ",
"HINDI " });
Person singer1 = new Person();
singer1.setName("DAVID ");
Person singer2 = new Person();
singer2.setName("JACOB ");
music.setSingers(new Person[] { singer1, singer2 });
Human man = new Human();
Person p = new Person();
p.setName(" JACK'S RAGING BULL ");
SomeGuy m = new SomeGuy();
m.setPerson(p);
man.setMan(m);
music.setHuman(man);
return music;
}
Outcome:
#######BEFORE#######
>>[>>DAVID ---<<, >>JACOB ---<<]---[ ENGLISH , FRENCH , HINDI ]---[>>ROCK ---X ---Y ---[SOME X DATA , SOME OTHER DATA X , SOME MORE DATA X , ]---[ SITAR , GUITAR , BASS , DRUMS ]<<, >>METAL ---A ---B ---[SOME Y DATA , SOME OTHER DATA Y , SOME MORE DATA Y , ]---<<, >>POP ---DONT ---KNOW ---[SOME Z DATA , SOME OTHER DATA Z , SOME MORE DATA Z , ]---<<]---[>>---[>>ROCK ---X ---Y ---[SOME X DATA , SOME OTHER DATA X , SOME MORE DATA X , ]---[ SITAR , GUITAR , BASS , DRUMS ]<<, >>POP ---DONT ---KNOW ---[SOME Z DATA , SOME OTHER DATA Z , SOME MORE DATA Z , ]---<<]<<, >>{Coach =>>CARTER ---<<, Name =>>JOHN JACKSON DOE ---<<}---[>>ROCK ---X ---Y ---[SOME X DATA , SOME OTHER DATA X , SOME MORE DATA X , ]---[ SITAR , GUITAR , BASS , DRUMS ]<<, >>METAL ---A ---B ---[SOME Y DATA , SOME OTHER DATA Y , SOME MORE DATA Y , ]---<<, >>POP ---DONT ---KNOW ---[SOME Z DATA , SOME OTHER DATA Z , SOME MORE DATA Z , ]---<<]<<]---=> JACK'S RAGING BULL <=<<
Number of spaces : 644
#######AFTER#######
>>[>>DAVID---<<, >>JACOB---<<]---[ENGLISH, FRENCH, HINDI]---[>>ROCK---X---Y---[SOME X DATA, SOME OTHER DATA X, SOME MORE DATA X, ]---[GUITAR, SITAR, DRUMS, BASS]<<, >>METAL---A---B---[SOME Y DATA, SOME OTHER DATA Y, SOME MORE DATA Y, ]---<<, >>POP---DONT---KNOW---[SOME Z DATA, SOME OTHER DATA Z, SOME MORE DATA Z, ]---<<]---[>>---[>>ROCK---X---Y---[SOME X DATA, SOME OTHER DATA X, SOME MORE DATA X, ]---[GUITAR, SITAR, DRUMS, BASS]<<, >>POP---DONT---KNOW---[SOME Z DATA, SOME OTHER DATA Z, SOME MORE DATA Z, ]---<<]<<, >>{Name=>>JOHN JACKSON DOE---<<, Coach=>>CARTER---<<}---[>>ROCK---X---Y---[SOME X DATA, SOME OTHER DATA X, SOME MORE DATA X, ]---[GUITAR, SITAR, DRUMS, BASS]<<, >>METAL---A---B---[SOME Y DATA, SOME OTHER DATA Y, SOME MORE DATA Y, ]---<<, >>POP---DONT---KNOW---[SOME Z DATA, SOME OTHER DATA Z, SOME MORE DATA Z, ]---<<]<<]---=>JACK'S RAGING BULL<=<<
Number of spaces : 111
There is a non-zero count of the number of spaces in the above trimmed output because I didn't make an effort to override toString of any collections (List, Set) or Map. There are certain improvements to the code I want to make but for your case the solution should work just fine.
Limitations (further improvements)
Cannot handle undisciplined syntax of properties (invalid getters/setters)
Cannot handle chained Collections: for example, List<List<Person>> - because of the exclusive support to disciplined getters/setters convention
No Guava collection library support
Building off #SwissArmyKnife I converted his simple String trimming function into an interface with a default method. So any object where you would like to use object.trim(), you just have to add "implements Trimmable".
Simple String trim interface: Trimmable.class
/**
* Utility interface that trims all String fields of the implementing class.
*/
public interface Trimmable {
/**
* Trim all Strings
*/
default void trim(){
for (Field field : this.getClass().getDeclaredFields()) {
try {
field.setAccessible(true);
Object value = field.get(this);
if (value != null){
if (value instanceof String){
String trimmed = (String) value;
field.set(this, trimmed.trim());
}
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
An object that we would like to be trimmable: Person.class (implements Trimmable interface)
public class Person implements Trimmable {
private String firstName;
private String lastName;
private int age;
// getters/setters omitted
}
Now you can use person.trim()
Person person = new Person();
person.setFirstName(" John ");
person.setLastName(" Doe");
person.setAge(30);
person.trim();
I made a simple method for trimming String values with Reflection API.
public Object trimStringValues(Object model){
for(Field field : model.getClass().getDeclaredFields()){
try{
field.setAccessible(true);
Object value = field.get(model);
String fieldName = field.getName();
if(value != null){
if(value instanceof String){
String trimmed = (String) value;
field.set(model, trimmed.trim());
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
I haven't bumped in to any problems with this one yet. I know its an old thread, but it might help somone whos is looking for something simple.
This is my code:
ArrayList<String> contentArray = new ArrayList<String>();
for(HashMap<ArrayList<String>, String> subTopicsEntry : subTopics){
contentArray = (ArrayList<String>) subTopicsEntry.get("Content");
}
It gives me error that arraylist cannot be cast to java.lang.string.
What is wrong here?
If i do it like this:
ArrayList<?> contentArray = new ArrayList<?>();
for(HashMap<?, ?> subTopicsEntry : subTopics){
contentArray = (ArrayList<?>) subTopicsEntry.get("Content");
}
it works
What is the difference ?
First of all Arrays.asList() returns List<String>, not ArrayList<String>.
You have to define your variable as this:
List<String> contentArray = new ArrayList<String>();
But that's not all the problems you have here.
As commenters have noted, you have (probably) misdeclared your Map. Perhaps you mean
ArrayList<String> contentArray = new ArrayList<String>(); // this initializer is unnecessary, btw
for(HashMap<String, ArrayList<String>> subTopicsEntry : subTopics){
contentArray = subTopicsEntry.get("Content"); // Note that a cast is no longer necessary
}
I question whether you really want ArrayLists here, but without seeing the rest of your code it's hard to say.
My answer code is:
package Examples;
import java.util.ArrayList;
import java.util.List;
public class ExampleClass
{
private List<String> _list;
#Override
public String toString() // override default method
{
String temp = "";
for (String s : this._list)
{
temp += (temp.length() == 0 ? "" : ", ") + s;
}
return "ExampleClass: [" + temp + "]";
}
public ExampleClass() // initialize this example class
{
this._list = new ArrayList<>();
this._list.add("Hello!");
this._list.add("Ciao!");
this._list.add("Good morning!");
this._list.add("Good afternoon!");
}
}
/*
// some code for using example
ExampleClass ec = new ExampleClass();
// prints next text to console:
// ExampleClass: [Hello!, Ciao!, Good morning!, Good afternoon!]
System.out.println(ec.toString());
*/
Have a nice day. Yuri