I speak Spanish, use the translator to ask this question, Sorry for the spelling.
Also, do not be like asking exactly what I want to do.
I want to create a list of an object passing through parameter.
public void createListUnknown(? Class myClass? or ? Object myObject?) {
List<myClass> my_list;
//or
List<myObject> my_list;
}
example use:
public class Model{
public String name;
public String age;
}
as it should be?
createListUnknown(?? MyModel ??)
Basically I want to create a list with an object that comes parameter to a function
An example where you want to apply is the following:
//final GsonModelUsuariosLoginGet gsonModelUsuariosLoginGet
//= gson.fromJson(responseData, GsonModelUsuariosLoginGet.class);
return gson.fromJson(responseData, httpObject.getObjectGet().getClass());
and
Object aClass = httpObject.getObjectGet().getClass();
List< httpObject.getObjectGetClass() > aClasses;
Type collectionType = new TypeToken<List<aClass>>(){}.getType();
final List<GsonModelArticulos> articulos = gson.fromJson(responseData, collectionType);
create list
public <T> List<T> makeList(Class<T> type) {
return new ArrayList<T>();
}
get type list
Using the Type interface.
private <T> Type getType(Class<T> type) {
Type typeOfObjectsListNew = new TypeToken<ArrayList<T>>() {}.getType();
return typeOfObjectsListNew;
}
Related
I have multiple types of objects, I'd like to generalise the 'id' of the objects in a way that will dynamically change what field is selected as the id.
Example
public class ObjectA{
//Attribute name attA
private String attA;
.... More attributes
public String getAttA(){
return attA
}
.....More getters/setters
}
public class ObjectB{
//Attribute named attB
private String attB;
.... More attributes
public String getAttB(){
return attB
}
.... More getters and setters
}
Id like to be able to run something like this:
Map<????, ????> customIdMap = new HashMap<>();
//We decide that ObjectA main attribute is AttA
customIdMap.add(ObjectA.class, ObjectA::getAttA);
//We decide that ObjectB main attribute is AttB
customIdMap.add(ObjectB.class, ObjectB::getAttB);
Then I'll be able to have a list of general objects and ill be able to retrieve their ids from the map if it is a known object with:
public String getCustomId(Object object){
if(customIdMap.contains(object.getClass()){
//Parameters are messed up, but this is the general idea of how
//i thought this would look
return customIdMap.get(object.getClass()).apply(object);
}
}
The code above does not run since getAttA is a call to a none static method in a static context so i assume this maybe should be wrapped in some kind of generic object.
Can it be done?
Preferably you change ObjectA and ObjectB to have a common interface. If that's not possible you can put them into a map like this:
Map<Class<? extends Object>, Function<Object, String>> map = new HashMap<>();
map.put(ObjectA.class, a -> ((ObjectA) a).getAttA());
map.put(ObjectB.class, b -> ((ObjectB) b).getAttB());
EDIT:
Or if you would like to encapsulate it into a typesafe heterogeneous container:
public static class ToIdMap {
private final Map<Class<?>, Function<Object, String>> map = new HashMap<>();
public <X> void put(Class<X> clazz, Function<X, String> func) {
map.put(clazz, (Function<Object, String>) func);
}
public String toIdString(Object o) {
return map.get(o.getClass()).apply(o);
}
}
EDIT2: Note that neither of these solutions work for subclasses, but it could be supported by traversing the class hierarchy in toIdString.
Your wording is a bit unclear, but I assume you want to get the ID of an object, even when they are different classes. This is the problem that interfaces solve.
You can create an interface, with one method called getId(), which will return the id. Then, you can just call getId() on any type of object with an id.
For example:
public interface Identifiable {
String getId();
}
public class ObjectA implements Identifiable {
// same for ObjectB
#Override
public String getId() {
return id;
}
}
Then, in your code:
Identifiable i1 = new ObjectA();
Identifiable i2 = new ObjectB();
System.out.println(i1.getId());
System.out.println(i2.getId());
EDIT:
It still looks like an interface is the cleanest way of solving your problem. For completeness, the following will work:
Map<Class, Function<?, String> map = new HashMap<>();
map.put(Object1.class, (Object1 o) -> o.getAttrA); // repeat for ObjectB
It can then be called with:
if (obj instanceof Object1) return map.get(Object1.class).apply((ObjectA) obj);
Ended up doing this weird solution:
class Mapping<T> {
private Function<T, String> idFunc;
public Mapping(Function<T, String> idFunc) {
this.idFunc = idFunc;
}
public String apply(T obj) {
return idFunc.apply(obj);
}
}
}
private Map<Class, Mapping> mappings = new HashMap<>();
mappings.put(ObjectA.class, new Mapping<>(ObjectA::getAttA);
mappings.put(ObjectB.class, new Mapping<>(ObjectB::getAttB);
public String getObjectID(Object object){
String id = null;
if(mappings.containsKey(object.getClass())){
id = mappings.get(object.getClass()).apply(object);
}
return id;
}
I want to create a generic method to return deserialized data. The idea is to pass through parameter a Type.class and when it deserialize using Gson, it returns a collection or a single object from Type.
For example:
public class Client {
String id;
String name;
/* getters and setters */
}
public class Account {
String number;
String bank;
/* getters and setters */
}
public class Main {
public static void main(String[] args) {
List<Client> clients = Utils.getList(Client.class, "");
Account account = Utils.getSingle(Account.class, "number = '23145'");
}
}
public class Utils {
public static Class<? extends Collection> getList(Class<?> type, String query) {
//select and stuff, works fine and returns a Map<String, Object> called map, for example
Gson gson = new Gson();
JsonElement element = gson.fromJsonTree(map);
//Here's the problem. How to return a collection of type or a single type?
return gson.fromJson(element, type);
}
public static Class<?> getSingle(Class<?> type, String query) {
//select and stuff, works fine and returns a Map<String, Object> called map, for example
Gson gson = new Gson();
JsonElement element = gson.fromJsonTree(map);
//Here's the problem. How to return a collection of type or a single type?
return gson.fromJson(element, type);
}
}
How can I return a single object from Type or a list of it?
First of all you need change method signature to generic type:
public static <T> List<T> getList(Class<T> type, String query)
and
public static <T> T getSingle(Class<T> type, String query)
getSingle method should start working, but for method getList you need to change implementation:
create Type listType = new TypeToken<List<T>>() {}.getType();
return gson.fromJson(element, listType);
you can find more information about com.google.gson.Gson from javaDoc
So here's a slightly tricky question (for me).
I have a generic object. Call it MyObject. This object has a method which returns something of the type T:
public class MyObject<T>
{
private T _t;
public MyObject(T t)
{
_t = t;
}
//...
public T get()
{
return _t;
}
}
(Obviously my "MyObject" does a bit more but that's the gist).
Now, I want to have a map of this type:
Map<String, MyObject<?>> m = new HashMap<>();
I want to be able to fetch maps using some predefined string name, and these maps can be of any MyObject. For example, I could call:
m.put("map_1", new MyObject<String>("String"));
m.put("map_2", new MyObject<Integer>(new Integer(3));
m.put("map_3", new MyObject<Long>(new Long(5));
etc.
But - and here's the tricky part - I want the map to "remember" the parameterized type of MyObject when I fetch some value from the map. Using
m.get("map_1");
would return a
MyObject<Object>
type, since the map was defined as containing
MyObject<?>
values. Thus:
m.get("map_1").get() // <-- This is an Object, not a String!
What modification (if any) is possible, in order to be able to get the correct - full - information regarding the MyObject fetched object, such that invoking the last line (m.get("map_1")) would return a
MyObject<String>
Thanks :)
Amir.
Typesafe Heterogeneous Containers from Joshua Bloch's Effective Java might work here. Basically you add a Class object to represent the type.
public class MyObject<T>
{
private T _t;
private Class<T> type;
public MyObject( Class<T> type, T t)
{
_t = t;
this.type = type;
}
//...
public T get()
{
return _t;
}
public Class<T> getType() { return type; }
}
Then you could do something like this:
public <T> T get( Map<String, MyObject<?>> map, String key, Class<T> type ) {
return type.cast( m.get( key ).get() );
}
Which is safe and will compile, but will throw a runtime error if you get the type wrong.
(Note I didn't actually compile that, so I might have syntax errors floating around. But most folks don't know how to use Class to cast objects.)
You can get the class.
Class c = m.get("map_1").get().getClass();
if (String.class.equals(c)) {
System.out.println("its a String");
}
Here is a full test.
public class GenericsTest {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
Map<String, MyObject<?>> map = new HashMap<>();
MyObject<String> obj = new MyObject<>("hello");
map.put("greeting", obj);
Class c = map.get("greeting").get().getClass();
if (String.class.equals(c)) {
System.out.println("its a String");
}
}
static class MyObject<T> {
T t;
public MyObject(T t) {
this.t = t;
}
T get() {
return t;
}
}
}
The type system only knows about types, not objects, and therefore can not distinguish "key1" from "key2", because both are of type String.
If keys have different types, the easiest way is to encapsulate a weakly typed map, and use reflective casts to prove to the compiler the types are correct:
class Favorites {
private Map<Class<?>,?> map = new HashMap<>();
<V> V get(Class<V> clazz) {
return clazz.cast(map.get(clazz));
}
<V> void put(Class<V> clazz, V value) {
map.put(clazz, value);
}
}
Favorites favs = new Favorites();
favs.put(String.class, "hello");
favs.put(Integer.class, 42);
favs.get(String.class).charAt(1);
If I have the following code:
public class DummyClass<T> {
public List<T> getList() {
return new ArrayList<T>();
}
public Set<List<T>> getListSet() {
return new HashSet<List<T>>();
}
}
and I have a DummyClass<?> dummy,
I can do
List<?> list = dummy.getList();
without any errors.
However,
Set<List<?>> listSet = dummy.getListSet();
gives the compile error:
Type mismatch: cannot convert from Set<List<capture#1-of ?>> to Set<List<?>>
for the line assigning dummy.getListSet().
Why can't I assign dummy.getListSet() to a Set<List<?>>?
However you can do following:
Set<? extends List<?>> listSet = listSet = dummyClass.getListSet();
See the excellent article Generics gotchas.
First is important to know, that the compiler replace ? operator with Object class. So when you write this:
DummyClass<?> dummy
your class definition will look like this:
public class DummyClass<Object>
and methods like this:
public List<Object> getList() {
return new ArrayList<Object>();
}
public Set<List<Object>> getListSet() {
return new HashSet<List<Object>>();
}
You can write
List<?> list = new List<Object>();
but not
Set<List<?>> set = new HashSet<List<Object>>();
PFB the code where i am trying to type cast list<object> to list<MyType> in java,
List<CoOffer> couponOffList = (List<CoOffer>)cioffers.getContent();
This getContent() returns list<object>.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"content"
})
#XmlRootElement(name = "CiOffers")
public class CiOffers{
#XmlElementRef(name = "CouponOffer", namespace = "http://www.ebi.com/webservices/", type = CouponOffer.class)
#XmlMixed
protected List<Object> content;
Now I have my java class CoOffer.
import java.io.Serializable;
public class CoOffer implements Serializable{
/**
*
*/
private static final long serialVersionUID = -3155316759617764263L;
private String cooffName;
public String getCooffName() {
return cooffName;
}
public void setCooffName(String cooffName) {
cooffName= cooffName;
}
}
How to cast list to list in java?
The property is annotated #XmlMixed which means it represents mixed content, so the cast you're asking about isn't guaranteed to be safe - the list may contain a mixture of CouponOffer objects (representing the elements) and java.lang.String objects (representing the mixed content text nodes in between elements).
You cannot cast it directly in a type-safe manner. Yes you can perform an unchecked cast, but that is not a good idea.
Now a List<Object> can contain any type of object, and List<MyType> can only contain objects of type MyType. So its not possible.
Solution is to make JAXB generate List<MyType> than List<Object>
You can create a helper method to cast return a new list.
public <T> List<T> castTo(List<Object> ol, Class<T> t) {
List<T> ret = new ArrayList<>();
for (Object o : ol) {
try {
ret.add(t.cast(o));
} catch (ClassCastException e) {
System.err.println(e.getMessage()+" "+o);
}
}
return ret;
}
And use it like that:
#Test
public void testCastTo() {
Class<MyType> t = MyType.class;
List<Object> ol = new ArrayList<>();
ol.add(new MyType(1));
ol.add("12");
ol.add(new MyType(123));
List<MyType> l = c.castTo(ol, t);
assertEquals(2,l.size());
}
If you are sure that returned object is List<CoOffer> you can cast it.
As;
(List<CoOffer>)(Object)cioffers.getContent();