How to extend objects contained in a List? - java

I have a List named resourceItems which containes ResourceItem objects.
public class ResourceItem {
private Long id;
private String name;
public ResourceItem(Long id, String name) {
this.id = id;
this.name = name;
}
// getters and setters...
}
public class SomeClass {
private List<ResourceItem> resourceItems = FindAllResourcesWebSerbice();
}
I would like to extend the objects in the List to include a boolean field named selected.
I've tried several variations of classes that extends ResourceItem (see below) including options using generics, but have not been successful. I would love a solution that uses generics for reuse.
public class ExtendedResourceItem extends ResourceItem {
private boolean selected = false;
public ExtendedResourceItem() {
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
}
public class SomeClass {
private List<ResourceItem> resourceItems = FindAllResourcesWebSerbice();
private List<ExtendedResourceItem> extendedResourceItem = resourceItems;
}
Any help is much appreciated.

Assuming ResourceItem implements equals and hashCode correctly, why not just keep a set of the ones that are selected:
Set<ResourceItem> selectedResourceItems = new HashSet<ResourceItem>();
Then you could add an item to the set when it's selected, remove it when it's deselected, and check to see if the set contains one when you need to know if it's selected.
This solution is very similar to Michael Myers' comment about using a Map<ResourceItem, Boolean>.

You should use composition, not inheritance here. From your description it sounds like ResourceItem is a domain object, but on screen, you should wrap it
class ScreenResourceItem {
ResourceItem item;
boolean selected;
}
Create a new list of ScreenResourceItem and put all the wrapped ResourceItems in it.
Generics and list covariance are not relevant here.

But using your snippet:
private List<ResourceItem> resourceItems = ... \\ some assignment;
private List<ExtendedResourceItem> extendedResourceItems = resourceItems;
is absolutely wrong. Since not any ResourceItem is guarantee to be also ExtendedResourceItem. (resourceItems list can contain objects that are ResourceItem but are NOT ExtendedResourceItem).
I don't see the point you want to reach, but if You want to transform resourceItems into list of resourceItems that have selected attribute, what about this concept:
public class ExtendedResourceItem {
private ResourceItem item = null;
private boolean selected = false;
public ExtendedResourceItem(ResourceItem item, boolean selected) {
this.item = item;
this.selected = selected;
}
// ... getters and setters
}
public class SomeClass {
private List<ResourceItem> resourceItems = FindAllResourcesWebSerbice();
private List<ExtendedResourceItem> extendedResourceItems = new ArrayList<ExtendedResourceItem>();
for (ResourceItem item: resourceItems) {
extendedResourceItems.add(new ExtendedResourceItem(item, false));
}
}

Is it the generics limits that are confusing? Try using the Upper Bounded Wildcards, e.g.
public class SomeClass {
private List<ExtendedResourceItem> extendedResourceItems = FindAllResourcesWebSerbice();
private List<? extends ResourceItem> resourceItems = extendedResourceItems;
}
Alternatively:
public class SomeClass {
private List<? extends ExtendedResourceItem> extendedResourceItems = FindAllResourcesWebSerbice();
private List<? extends ResourceItem> resourceItems = extendedResourceItems;
}
More information about wildcards Wildcards and Subtyping.

Related

private class ArrayList (set)

I have a class named "classroom" and i want send one arraylist with classroom.setMaterias(Arraylist). Is this code:
Class Clasroom
public class Aula implements java.io.Serializable {
private String nombre;
private String grupo;
private int tutor;
ArrayList<String> materias = new ArrayList<String>(); // ¿How create arraylist?
public Aula() {
// Constructor
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
I would like to know if I could, for example, send an "arraylist" through a SET and then make the "arraylist" that I created previously in my class "classroom" be exactly the same
I would not know how to create the arraylist, or the set or get methods. Can you help me please?
PD: This is the JSON ARRAY i talking about:
if (obj.has("materias")) {
JSONArray materias = obj.getJSONArray("materias");
datos.setArrayList(materias);
// System.out.println(materias); // ["DWES","DWEC","IW","DAW","IE"]
Class Clasroom
public class Aula implements java.io.Serializable {
private String nombre;
private String grupo;
private int tutor;
ArrayList<String> materias; // ¿How create arraylist?
public Aula() {
// Constructor
this.setArrayList(new ArrayList<>()); //Here you initialize the arraylist when you create an instance of this class.
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
//Here are the getters and setters.
public ArrayList<String> getList(){
return this.materias;
}
private void setArrayList(ArrayList<String> list){
this.materias = list;
}
The proper way of doing it is using getters and setters and using List interface rather than ArrayList<> directly.
List<String> materias = Collections.emptyList();
public Aula() {
// Constructor
}
public List<String> getMaterias() {
return materias;
}
public void setMaterias(List<String> materias ) {
this.materias = materias ;
}
public void addMaterias(String materia) {
materias.add(materia);
}
You can have additional addMaterias() method to add entries to your List.
public class Aula implements java.io.Serializable {
private List<String> materia = new ArrayList<>();
...
public void setMateria1(final List<String> aMateria) {
this.materia = aMateria;
}
public void setMateria2(final List<String> aMateria) {
this.materia.clean();
this.materia.addAll(aMateria);
}
}
setMateria1() replaces the list with the given argument, thus any changes (EG deletion of items,) made later to the one, is reflected in the other.
While setMateria2() copies the argument's items, thus deletion or insertion to any of them does not change the other one.
Also ArrayList is a concrete implementation of the interface List. It is preferable to declare variables as the base class or interface, instead of a concrete implementation.
public class Aula implements java.io.Serializable {
ArrayList<String> materias = new ArrayList<String>();
...
public ArrayList<String> getMaterias(){
return materias;
}
public void setMaterias(JSONList materias) throws JSONException {
materias.clear();
for(int i=0;i<materias.length();i++)
this.materias.add(materias.getString(i));
}
}
And put the exact same code into the classroom class.
Second way is to set the Lists in the constructor:
public class Aula implements java.io.Serializable {
ArrayList<String> materias = new ArrayLis<>();
...
public Aula(JSONList materias) throws JSONException {
for(int i=0;i<materias.length();i++)
this.materias.add(materias.getString(i));
}
public ArrayList<String> getMaterias(){
return materias;
}
}
Again same for classroom. And than you create them eg.
Aula aula = new Aula(materias);
Classroom classroom = new Classroom(materias);
This is assuming you have Strings in your list. Otherwise it depends on your data in the list.
If it contains other Lists it they need to be merged or skipped and so on...
If the json is not all Strings(e.g. has Sublists and Objects) and it should match the actual structure of your json I'd need that structure too and most probably an Arraylist of Strings might be the wrong Container for such a json - tree.
btw. better change classroom to Classroom(capital C for the classname) ...

How can I ensure an argument is a class field (Java)?

I am creating an API that returns a list of Cars. The API user must be able to request that the list be filtered and sorted by a certain attribute (field) of the Cars class. How can I do that?
class Car {
public final String model;
public final String color;
public Car(String m, String c) {
model = m;
color = c;
}
}
class CarListRequest {
public final String sortBy;
public final String filterBy;
public final List<String> filterList;
public CarListRequest(String s, String f, List<String> list) {
sortBy = s;
filterBy = f;
filterList = list;
}
}
Is there a way to restrict, using Java language features, that sortBy and filterBy Strings cannot contain any other values than attributes (fields) of the Car class?
I know that I could use an enum to declare all attributes of Car however, that causes a duplication of Strings which I would like to avoid.
#hmc_jake 's reflection suggestion is quite valid. However, if you want to avoid reflection, you could do it using a class hierarchy:
class CarAttribute {
private String attrib;
public CarAttribute(String att){
attrib = att;
}
// add getters and/or setters for attrib ...
}
class CarModel extends CarAttribute {
}
class CarColor extends CarAttribute {
}
class Car {
public final CarModel model;
public final CarColor color;
public Car(CarModel m, CarColor c) {
model = m;
color = c;
}
}
class CarListRequest {
public final CarAttribute sortBy;
public final CarAttribute filterBy;
public final List<CarAttribute> filterList;
public CarListRequest(CarAttribute s, CarAttribute f, List<CarAttribute> list) {
sortBy = s;
filterBy = f;
filterList = list;
}
}
Using Reflection in Java, it is possible to inspect a class's fields.
When, for example, s is passed in, you can perform a check on the argument like so:
for (Field field : Car.class.getFields()) {
if (field.getName().equalsIgnoreCase(s)) {
Do something here to signal that s
was a valid Field of the Car class.
}
}
Doing this allows you to reflectively inspect the Car class in order to verify that the argument passed in is in-fact a field of that class.
Note, however, that if possible you should go with the enum or class hierarchy as reflection might be a little bit overkill for what you're trying to accomplish.

How to extend a list in java to store additional metadata and force it to accept only one type of objects?

In addition to the included items, I have to store the name and the id of the List inside itself. Thus i extended an ArrayList as follows:
class MyList<E> extends ArrayList<E>{
private int id;
private String name;
MyList(int id, String name){
this.id = id;
this.name = name;
}
id getId(){ return id; }
String getName(){ return name; }
}
Now I realized, that this extension will only hold one specific type of objects. So how can I remove the generic character of my list?
class MyList<MyObject> extends ArrayList<E>
class MyList<MyObject> extends ArrayList<MyObject>
...and so on fails. I want to instantiate my list by
MyList mylist = new MyList();
...and it should automatically accept only MyObjects...
(Would it be better to create a wrapper which holds an ArrayList in addition to the meta? But because it is still a list, why remove all list-typical capabilities...)
You'll need
class MyList extends ArrayList<MyObject>
When you declare a type parameter for your class declaration like so
class MyList<MyObject> ...
the type MyObject> is not your type, it is a type variable that also has the name MyObject.
What you want, is to use your MyObject type as a type argument for the ArrayList type parameter as shown above.
But, as others have suggested, composition is probably a better way to do this, ie the wrapper you suggested in your question.
As has been answered already, the correct declaration would be
class MyList extends ArrayList<MyObject>
Even though you have no interest in overriding any ArrayList methods, you should consider composition over inheritance for this type of scenarios.
Example:
class MyList implements Iterable<MyObject> {
private final int id;
private final String name;
private final List<MyObject> list;
MyList(int id, String name){
this.id = id;
this.name = name;
this.list = new ArrayList<>();
}
int getId() { return id; }
String getName() { return name; }
MyObject get(int i) { return list.get(i); }
void add(MyObject o) { list.add(o); }
void remove(MyObject o) { list.remove(o); }
void remove(int i) { list.remove(i); }
void set(int i, MyObject o) { list.set(i, o); }
boolean contains(MyObject o) { return list.contains(o); }
int size() { return list.size(); }
#Override
Iterator<MyObject> iterator() { return list.iterator(); }
}
With this:
You can easily switch the ArrayList for a LinkedList, or any other list;
You control the methods this class offers;
If you like the chaining style, you may change those void for MyList;
etc.

Creating a parent class that contains an object restricted to a child class

I am attempting to make a parent class that has an object element within it, but I want to restrict this object to a type that extends the parent class. I have tried using generics in the form of
<T extends ParentClass> T
but this doesn't work.
Here is an example of what I am I currently working with.
public class ParentEvent {
private Object event;
private String type;
private Date time;
private String id;
public ParentEvent() {
event = null;
type = null;
time = null;
id = null;
}
public ParentEvent(String type, String id, Date time, Object event) {
this.event = event;
this.type = type;
this.time = time;
this.id = id;
}
public Object getEvent() { return event; }
public void setEvent(Object event) { this.event = event; }
// Other get/set methods removed for clarity
}
How would I go about restricting the Object referenced in the above code to one that extends the parent class?
Do you mean this:
public class ParentEvent<T extends ParentEvent<?>>
{
private T event;
...
public T getEvent() {...}
...
public void setEvent(T event) { ... }
}
And then, the child is:
public class ChildEvent extends ParentEvent<ChildEvent>
This doesn't need generics. private ParentEvent event; should do exactly what you're after. You may also want to make ParentEvent abstract.

How to dynamically retrieve a constant in java?

I have several interfaces all with the same constants - ID and ROOT. I also have a method into which I pass an object that will be an implementation of one of these interfaces.
How can I dynamically retrieve the value of the constant depending on the class passed in - i.e. I want to do something like the following:
public void indexRootNode(Node node, Class rootNodeClass)
{
indexService.index(node, rootNodeClass.getConstant('ID'),
rootNodeClass.getConstant('ROOT'));
}
In PHP this is easy, but is this possible in Java? I've seen this problem solved using accessors on the constant, but I want to retrieve the constant directly. Annotations won't help me here either.
Thanks
This can be achieved using reflection (also see corresponding javadoc).
public void indexRootNode(Node node, Class rootNodeClass)
{
Field idField = rootNodeClass.getField("ID");
Object idValue = idField.get(null);
Field rootField = rootNodeClass.getField("ROOT");
Object rootValue = rootField.get(null);
indexService.index(node, idValue, rootValue);
}
Maybe you may additionaly have to cast the values to the corresponding type.
Please read chapter 19 use interfaces only to define types from Joshua Bloch's Effective Java (in fact, please read the entire book)
Constants do not belong in an interface!!! Constants should be tied to implementing classes, not interfaces.
Either use non-constant methods:
// the implementing classes can define these values
// and internally use constants if they wish to
public interface BaseInterface{
String id(); // or getId()
String root(); // or getRoot()
}
public interface MyInterface1 extends BaseInterface{
void myMethodA();
}
public interface MyInterface2 extends BaseInterface{
void myMethodB();
}
or use an enum to tie things together:
public enum Helper{
ITEM1(MyInterface1.class, "foo", "bar"),
ITEM2(MyInterface2.class, "foo2", "baz"),
;
public static String getId(final Class<? extends BaseInterface> clazz){
return fromInterfaceClass(clazz).getId();
}
public static String getRoot(final Class<? extends BaseInterface> clazz){
return fromInterfaceClass(clazz).getRoot();
}
private static Helper fromInterfaceClass(final Class<? extends BaseInterface> clazz){
Helper result = null;
for(final Helper candidate : values()){
if(candidate.clazz.isAssignableFrom(clazz)){
result = candidate;
}
}
return result;
}
private final Class<? extends BaseInterface> clazz;
private final String root;
private final String id;
private Helper(final Class<? extends BaseInterface> clazz,
final String root,
final String id){
this.clazz = clazz;
this.root = root;
this.id = id;
};
public String getId(){
return this.id;
}
public String getRoot(){
return this.root;
}
}
// use it like this
String root = Helper.fromInterfaceClass(MyInterface1.class).getRoot();

Categories