I have two classes A and B, both classes have n number of fields. I need to map only specific fields from object of A to B using Streams API. I have only getters and setters in both classes and I don't have possibility of making changes in class A and B.
class A {
private String name;
private int age;
private String city;
}
class B {
private String name;
private String country;
}
I have a bunch of A object in an ArrayList. I need to create List of object B and the object should have only value for name field.
I have similar buisness use case, where I will be I will be having n number of fields and I need to map multiple fileds.
Below code which I have tried,
private List<B> mapAtoB(List<A> a) {
return a.stream().map(m -> mapToB(m)).collect(Collectors.toList());
}
private B mapToB(A a) {
B b = new B();
b.setName(a.getName());
return b;
}
Is there any best solution to achieve, other than the above impl or create and map using constructor.
Best way to map between classes is using a mapping library like MapStruct.
In case you still wanna do it manually then you can using reflection and FieldUtils from the Apache Commons Lang 3:
public List<Obj2> mapObj1toObj2(List<Obj1> source) {
return source.stream().map(obj1 -> {
Obj2 obj2 = new Obj2();
Arrays.asList(obj1.getClass().getDeclaredFields()).forEach(field -> {
try {
FieldUtils.writeField(obj2, field.getName(), FieldUtils.readField(field, obj1, true), true);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
return obj2;
}).collect(Collectors.toList());
}
Related
I have a Pojo class with all numeric fields
public class Pojo {
private long field1;
private long field2;
private long field3;
private long field4;
private long field5;
private double field6;
private double field7;
private double field8;
private double field9;
}
And there is a list of Pojo, I want map this list to one Pojo object which will contain in its field the of pojos foe, list. I mean someething like this :
public static void main(String[] args) {
List<Pojo> pojoList = getPogoList();
Pojo pojoInSum = reduceAllFields(pojoList);
}
What is the simplest way to reduce all fields of pojos from list without reflection?
You could use the Stream#reduce method:
public void reducePojoList() {
PojoReduce pojoReduce = new PojoReduce();
List<Pojo> pojoList = Arrays.asList(
new Pojo(3L, 4.0),
new Pojo(6L, 1.1));
Optional<Pojo> reducedPojo = pojoList.stream().reduce(this::combine);
reducedPojo.ifPresent(System.out::println);
}
private Pojo combine(Pojo pojo1, Pojo pojo2) {
return new Pojo(
pojo1.getLongField() + pojo2.getLongField(),
pojo1.getDoubleField() + pojo2.getDoubleField()
);
}
You would have to update the combine method for every field you add though. You'd also be creating a lot of new objects.
The simplest way is to write a method in that pojo. Because if you are modeling a thing in a class you should expose behavior and not data.
But I doubt that is what you are looking for so you might want to look at reflection.
Basically you retrieve all the fields of a class, get the values for the instance and then sum them in a loop or stream.
I have the follow Objects:
public class Processitems{
private String priority;
private Date date;
private Integer status;
}
public class OrderItems {
private String orderItem1;
private String orderItem2;
}
orderItem1, orderItem2 is "priority" or "date" or "status"
Now I must sort List<ProcessItem> by conditions of OrderItems. I mean if orderItem1 = "priority" then sort List<ProcessItem> by priority, if orderItem = "date" then sort List by date,... and if sort by orderItem1 is unavailable then sort by orderItem2 . How could I use Comperator.comparing(orderItem1).thencomparing(orderItem2) ?
One thing you can do is add a method to OrderItems that builds the appropriate Comparator object for you. Let's call it getComparator.
Since you have two fields you want to sort by - orderItem1 and orderItem2 - it's useful to create a helper method that creates a comparator for any field you want to pass in.
Then you can use it to create two comparators and compose them together, or do whatever you want.
public class OrderItems {
private String orderItem1;
private String orderItem2;
private Comparator<Processitems> createComparatorForField(String field) {
switch (field) {
case "priority": return Comparator.comparing(p -> p.priority);
case "date": return Comparator.comparing(p -> p.date);
case "status": return Comparator.comparing(p -> p.status);
}
throw new IllegalArgumentException(field);
}
Comparator<Processitems> getComparator() {
if (orderItem1 != null) {
Comparator<Processitems> order1 = createComparatorForField(orderItem1);
Comparator<Processitems> order2 = createComparatorForField(orderItem2);
return order1.thenComparing(order2);
}
else return createComparatorForField(orderItem2);
}
}
We can take use of java.lang.reflect.Field for your case:
// OrderItem can be detrmined at runtime based on your logic
String orderItem = "priority";
Comparator<Processitems> comparator = new Comparator<Processitems>(){
public int compare(Processitems p1, Processitems p2){
try {
Field processItem = p1.getClass().getField(orderItem);
Comparable<Object> comparablep1
= (Comparable<Object>) processItem.get(p1);
Comparable<Object> comparablep2
= (Comparable<Object>) processItem.get(p2);
return comparablep1.compareTo(comparablep2);
} catch(Exception e) {
throw new RuntimeException(
"No field present with " + orderItem, e);
}
};
}
I have a class like this:
public class Example {
private String a;
private Integer b;
private Boolean c;
private List<AnotherClass> d;
}
and I want to convert it to something like this:
[
{
name: "a",
value: "a value"
},
{
name: "b",
value: "1",
},
{
name: "c",
value: "true",
}
]
So, I create a class like this:
public class Test {
private String name;
private String value;
}
I want to have a method to iterate through the Example class so it will produce the Test class without including d attribute. How to achieve that?
This is something you can do easily with reflection. In the example below, I renamed class Test to Property because it represents a key-value pair. If you are happy with using whatever toString() returns as the value for a field, then the solution is pretty simple:
public class Property {
private final String name;
private final String value;
public Property(String name, String value) {
this.name = name;
this.value = value;
}
public static List<Property> toProperties(Object object, String... fieldNames)
throws ReflectiveOperationException
{
ArrayList<Property> properties = new ArrayList<>();
for( String fieldName : fieldNames ) {
Field field = object.getClass().getDeclaredField(fieldName);
properties.add(new Property(fieldName, field.get(object).toString()));
}
return properties;
}
public String toString() {
return String.format("%s: \"%s\"", name, value);
}
}
This sample requires you to specify the names of the desired fields explicitly, for example:
List<Property> properties = Property.toProperties(myExample, "a", "b", "c");
If you'd rather have the fields be auto-detected based on some criterion (for example all primitive and String-typed fields, then you could add this logic within toProperties and get rid of the varargs.
you would need to have some appropriate getters in class Example, and a proper constructor in class Test to initialize the object instance variables like
public Test (String name, int value) {
this.name = name;
this.value = value'
}
Then for each instance of class Example - lets say you have multiple of those in an array or list - you could iterate over them, retrieve the values you want via the getter methods, and initialize one Test object for each one, eg
List<Test> yourListOfTestInstances = new ArrayList<>();
for (Example exampleObject : yourExampleObjectsListOrArray) {
yourListOfTestInstances.add(new Test(exampleObject.getA() , exampleObject.getB()));
}
Then for each created Test instance inside your ArrayList, you could easily build your JSON as needed (even though I do not fully understand why you even need at all this intermediate Test class to do that)
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 have a data structure in Java that I am populating via different methods. One method populates it from an API, another method populates it from parsing some HTML, another populates it a different way, etc. Basically, a method for every data source that could populate it. What I'm wondering is, what design patterns are available in Java for this? What's the best/cleanest OOP approach to this problem?
E.g.,
public class Data {
private String foo;
private List<String> bar;
private Map<String, Integer> baz;
public Data (String foo, List<String> bar, Map<String, Integer baz) {
this.foo = foo;
this.bar = bar;
this.baz = baz;
}
// Setters and Getters here, etc
}
public class FacebookParser {
private Document dom;
public static Data parse(Document dom) {
// Parse document
// Create Data object
return Data;
}
}
public class TwitterParser {
private Document dom;
public static Data parse(Document dom) {
// Parse Twitter
Data d = new Data(stuff from twitter);
return d;
}
}
You want a Data and it is represented in different forms. The part that you are interested in should be defined in an abstract way. So making the Data an interface is a good point for starting.
public interface Data {
String getFoo();
List<String> getBar();
Map<String, Integer> getBaz();
}
This data is obtained from different providers. The common thing is we need someone to provide Data. In the end, the only thing we are interested in is the Data itself, not how it is parsed or provided. So we need a simple DataProvider interface.
public interface DataProvider {
Data createData();
}
Now we can implement the provider classes those know how to fetch, parse, process etc. the data. Provider classes should not be dealing with how to convert the provider specific data into our common Data interface. They are only responsible for creating a Data implementation that they know.
public class FacebookDataProvider implements DataProvider {
public Data createData() {
FacebookSpecificInfo x = ...
FacebookData data = new FacebookData();
// Note that this class does not know anything about foo, bar and baz.
// We are still Facebook context.
data.setName(x.getName());
data.setValues(x.getValues());
data.setHeaders(x.getHeaders());
return data;
}
}
class FacebookData implements Data {
private String name;
private List<String> values;
private Map<String, Integer> headers;
void setName(String name) { this.name = name; }
void setValues(String values) { this.values = values; }
void setHeaders(String headers) { this.headers = headers; }
// This is the part where we switch the context and convert
// Facebook specific data into our expected Data
// ie. Facebook's name field corresponds my foo field.
public String getFoo() { return name; }
public List<String> getBar() { return values; }
public Map<String, Integer> getBaz() { return headers; }
}
What you can do is have a separate class for setting the values of the Data class.
You can have something like this :
public class DataPopulator{
public void setTwitterData(Data d){
//your data
}
public void setFacebookData(Data d){
//your data
}
}
This is something similar to Adapter Design pattern, though not exactly same.
You can have a look at it here.