Bind objects in a Set collection - java

I have a form which fills some objects of a Collection. I had the collection implemented with a List (an everything worked good), but now I want to use a Set. I have a property editor registered to create the objects. The problem is that I don't know what is the syntax I must use to populate the objects of the Set.
public class MyObject(){
Set<OtherObject> otherObjects = new HashSet();
}
I have tried with the syntax in the form tags, like the syntax a list:
name="otherObjects['${status.index}']"
and like the syntax for a map:
name="otherObjects['${id}']"
but both come to an error because "Property referenced in indexed property path 'otherObjects[0]' is neither an array nor a List nor a Map"
I have also tried with
name="otherObjects"
but this doesn't fill the objects.
Can anyone tell me how to bind the data to the objects in a Set.
Thanks

According to the documentation on data binding, you can only user the bracket notation to bind to nested objects in a "naturally ordered collection". A set doesn't qualify.

Can't you use the old syntax in the form tags and add a getter that will return a set of objects?
public class MyObject(){
List<OtherObject> otherObjectsList = new ArrayList<OtherObjects>();
public Set<OtherObject> getOtherObject()
{
return new HashSet<OtherObject>(otherObjectsList);
}
}

Related

Using Generic Input in a Functional Interface

I have an object that's designed to paginate a list and send a page of the results to a user. However, I want to be able to use Functions to pass behavior to this object. The behavior will be used by the object to dynamically generate the content of the lines using methods inside the objects in the list.
public class InteractiveJSONList<T> {
private final List<T> list;
private List<Function<T, Object>> formatArgFunctionSequence;
// ... Irrelevant code truncated.
// Constructor
public InteractiveJSONList(List<T> list) {
this.list = list;
}
}
I'm using generics to define the type of list, and likewise, the input type of the function. However, when attempting to define the Function as input to a method, NetBeans doesn't seem to recognize the input object as the correct type (it simply treats it as an instance of Object).
This code snippet resides inside an instance method in InteractiveJSONList. The method is designed to extract information from each item in the list and use the results as format arguments for String.format later on.
for (T item : itemsList) {
index++;
// Create a new JSON Message.
new JSONMessage(resultLinesBaseMessage)
.setFormatArguments(index, stringFunctionSequence.stream()
.map(o -> o.apply(item))
.collect(Collectors.toList())
.toArray(new Object[stringFunctionSequence.size()]))
}
I'm using Java 8's Stream methods to apply the function using each item in the list as input, then collecting the results and submitting them as an array for a varArgs method to use later in String.format.
Finally, this is an attempt to implement the mechanism.
List<String> data = ... //Using Strings at this point, but could be anything.
new InteractiveJSONList<String>(data)
.setStringBuildingSequence(input -> input.substring(0,5));
I'm only using String and its method substring as an example for how I want this mechanism to work. Certain objects in this list will be more complicated than Strings, and will have getters for variables inside the object. I want to define the behavior required to get variables from within the items in this list, and then use them to generate dynamic results. However, NetBeans won't recognize input as a member of String, and I subsequently am not able to use String's methods. input is only recognized as an object, even though InteractiveJSONList's generic type T is defined as a String when the object was created.
Am I setting up generics incorrectly? I might be led to think it's as simple as that, however, I tested this instead:
List<String> data = ... //Using Strings at this point, but could be anything.
Function<String, Object> testFunction = input -> new InteractiveText(input.substring(0, 8));
new InteractiveJSONList<String>(data)
.setStringBuildingSequence(testFunction);
And it compiled and ran correctly.
Any advice? Also, if this is a terrible practice for my desired purpose, please let me know. Thank you!

Java: No ArrayList modifications from outside classes

I use an ArrayList in one of my Java project's classes. The class keeps track of whether the list has been changed and offers public methods to add and remove elements from the list that automatically set the variable to "changed".
So far the list is public because I want my list to be publicly readable from everywhere. But I only want the class that owns the list to be able to modify it. So no modifications from outside classes. Is that possible? If so, how?
Usually for access control you'd probably use getter and setter methods. But even with a getter method and the list set to private another class could still do getList().remove(element) and thereby modify the list from the outside without the class noticing that the list was changed.
Make your ArrayList field private, but have your getter return Collections.unmodifiableList(list), which provides an unmodifiable view.
This will allow external code to treat it as a normal List, using for each loops and so on, but will disable modification operations. Additionally, unmodifiableList returns a view in constant time.
This is literally the exact use case it was designed for. Javadoc:
This method allows modules to provide users with "read-only" access to internal lists. Query operations on the returned list "read through" to the specified list, and attempts to modify the returned list, whether direct or via its iterator, result in an UnsupportedOperationException.
Make your List private and add getter method:
public List getList(){
return new ArrayList(yourPrivateList);
}
You can make the ArrayList member private, and instead of a getter that returns the ArrayList, have a getter that accepts an index i and returns the i'th element of the ArrayList.
public class Test
{
private List<String> list = new ArrayList<String>();
public getString (int i)
{
// you might want to add some validation of i here
return list.get(i);
}
}
getString allows the users of your class to access any element of the list without being able to modify it.
If you want to allow your users to iterate over the list without being able to modify it, you can add a getSize() method to return the size of the list (which would allow the users to iterate over the list using the regular for loop), or your class can implement Iterable (without supporting the remove operation).
You have couple of options here:
The getter that returns the ArrayList can clone before returning the object. This way, even if the outside entity modifies the object, they'll end up modifying the clone - not your original object. Note: The clone operation can be costly. I'd suggest the below option.
Use Collections.unmodifiableList(..). Check the documentation here.
Or as other answers suggest: roll out your own methods for access and iteration.
I think your best option here is to keep your List private and add a getter method that returns a copy of the List, but not the List itself. For example:
public class EncapsulationTest {
private List<Object> privateList = new ArrayList<Object>();
// Your constructors and methods to track list
// modification here ...
public List<Object> getList() {
// Maybe you need a null check here
return new ArrayList<Object>(privateList);
}
public void addElement(Object newElement) {
this.privateList.add(newElement);
// Set your 'changed' variable to true
}
public void removeElement(Object element) {
this.privateList.remove(element);
// Set your 'changed' variable to true
}
}
If you do this, you can still read an exact copy of the List, but you can't modify the List itself. Well, actually you can modify the returned List, but as it is a different object, the changes won't affect your object's List.
I hope it helps.

Return type of multi-valued Entity properties

I'm using App Engine's Datastore entities in my current project, and I have a multi-valued property for one of the entities. Now, my question is simple, if I store String objects as the values in the multi-value property by passing a String ArrayList as the value in the setProperty("myPropertyName", myArrayList) of my entity, what object will I receive when I run the following:
myEntity.getProperty("myPropertyName");
From my observation it doesn't seem to return an ArrayList, even though ArrayList is a Collection and, according to the documentation, getProperty() returns a Collection object.
The list of supported types can be found here: https://developers.google.com/appengine/docs/java/datastore/entities#Java_Properties_and_value_types.
Strongly consider using a JSON string as GAEfan suggested.
Edit:
According to the OP's comment below, you can store and get multiple values in the datastore as follows:
myEntity.setProperty("myPropertyName", myArrayListOfStrings)
List<String> myValues = myEntity.getProperty("myValueName");

Help need with transforming Java lists/collections or something

I have a list of objects returned from getJdbcTemplate().query
that look like this
object(test,test,test,1)
object(test,test,test,2)
object(test,test,test,3)
How can I transpose these into one object that looks like this
object(test,test,test,list<t>({1,2,3}))
Hopefuly you get the idea from my ropey psuedo object representation :)
I think using RowMapper can be a little painful. Perhaps, you can do something like this (by the way, this is my pseudo):-
List<Map> rows = getJdbcTemplate().queryForList(sql);
MyObject obj = null;
for (Map row : rows) {
// configure the first 3 fields upon object creation.
if (obj == null) {
obj = new MyObject(row.get("firstField"), row.get("secondField"), row.get("thirdField"));
}
// basically add each item into the list
obj.addToList(row.get("fourthField"));
}
JdbcTemplate deals with rows, so you need a RowMapper to extract the values and convert them into a List of a custom type (implement a class that corresponds to this structure object(test,test,test,1)). Then you can work on the extracted values and assemble your new object from the list values.
Reference:
Examples of JdbcTemplate class
usage
JdbcTemplate javadoc
RowMapper<T> javadoc
Couldn't you use a 2 dimensional array?
http://www.willamette.edu/~gorr/classes/cs231/lectures/chapter9/arrays2d.htm
I'm kind of a noob at java so if I'm not correct, please excuse my ignorance.
Extend your Object Model.
You need to create a new object, similar to the one you are creating with the individual value argument, which instead takes a list or a collection as the final argument. Instead of storing a single value there, your object will store a list or a collection there. If this list or collection will be immutable once the object has been created, you should consider converting the data to an int[] before storing it.
Then, build whatever methods you need on this new object. You can even write a method to return an array of the old objects, where each object has only one value in it.

Java test specific property of an object using Collection.contains()

In Java how to test if a Collection of objects contains an object depending on one of its properties.
For example I would like to test if Collection<myObjects> contains an instance of myObjects which has myObjects.name = "myName".
You will have to iterate and do the comparison.
Consider using a Map.
Map<String,myObjects> myMap = new HashMap<String,myObjects>();
myMap.put(myObject.name,myObject);
You can use apache collections, they provide a bunch of handy features including predicate:
public class MyPredicate implements Predicate {
public boolean evaluate(Object input) {
return (MyObject).name = "myName";
}
}
then you can test your collection using :
CollectionUtils.find(myCollection, new MyPredicate());
This will return the first object matching the predicate or null if none matches it.
If you have control on how the data is collected, you can also have some kind of "reverse index" on that property; The index can be a mapping between name and a set of myObjects with that name. This way, you can efficiently retrieve all items with a given name. You can add more indexes the same way.

Categories