Generic method to take different class objects - java

I have 3 class(techspecs, packages, and features) objects where they all share the same fields. The fields are big and instead of repeating setting the fields of each field 3 times(which ends up looking like duplicates), I would like to pass the class objects into one method that uses the generic object to setting the object fields.
I tried passing the class object as a generic but then i dont have access to its members. This is what i tried
Packages packagesFeatures = new Packages();
TechSpecs techSpecsFeature = new TechSpecs();
packagesFeatures = addFeatures(Packages.class, packagesFeatures, vehFeatures);
techSpecsFeature = addFeatures(TechSpecs.class, techSpecsFeature, vehFeatures);
Then
private <T> T addFeatures(Class<T> clazz, T obj, VehicleFeature vehFeatures) {
T inst = null;
try {
inst = clazz.getDeclaredConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
if (inst instanceof Packages) {
obj = (T) new Packages();
}
if(inst instanceof TechSpecs){
obj = (T) new TechSpecs();
}
if(inst instanceof Features){
obj = (T) new Features();
}
//then somthing like:
//obj.setFeatureId(vehFeatures.getFeatureId());
// obj.setFeatureKey(vehFeatures.getFeatureKey());
// obj.setFeatureCode(vehFeatures.getFeatureCode());
return obj;
EDIT
Each of the 3 classes extend BaseFeatures
public abstract class BaseFeatures {
private String featureId;
private String featureKey;
private String featureCode;
private String subSectionId;
private String subSectionName;
private String featureIdName;
private Integer subSectionRank;
private Integer featureImgClassificationId;
private String featureImgClassification;
private boolean has3DAnimation;
private String sectionId;
private String searchKeys;
private String description;
private String featureName;
private double featureRank;
private String geoId;
private String ecc;
private String specSegments;
private String featureIconType;
private String featureIconText;
private double featureValue;
private boolean standardCertain;
private boolean built;
private List<String> featureKeyAnswers;
private boolean isNumeric;
private boolean adasFeature;
private List<String> icCodeAnswers;
private String featureKeyNoBrand;
private List<StyleInfo> styles;
private List<String> optionCodes;
private List<String> changeOptions;
//getters and setters.
Here is one of the classes.
public class TechSpecs extends BaseFeatures {
private String techSpecs;
public void setTechSpecs(String techSpecs) {
this.techSpecs = techSpecs;
}
public String getTechSpecs(){
return techSpecs;
}
}
All of these fields need to be set in the class object of all 3 classes
EDIT 2
VehicleFeature Class is a standalone class
#JsonInclude(JsonInclude.Include.NON_NULL)
public class VehicleFeature {
private String section;
private String subSection;
private String featureName;
private String subSectionId;
private String sectionName;
private String subSectionName;

If it were me, I would simplify your addFeatures(...) method to something like:
private <T> T addFeatures(Class<T> clazz, BaseFeatures theseFeatures) {
T obj = null;
try {
obj = clazz.getDeclaredConstructor(BaseFeatures.class).newInstance(theseFeatures);
} catch (ReflectiveOperationException roe) {
roe.printStackTrace();
}
return obj;
}
I'd add these two constructors to BaseFeatures:
public abstract class BaseFeatures{
protected String featureId;
protected String featureKey;
protected String featureCode;
/*...*/
protected BaseFeatures(String featureId, String featureKey, String featureCode){
this.featureId = featureId;
this.featureKey = featureKey;
this.featureCode = featureCode;
}
protected BaseFeatures(BaseFeatures features){
this.featureId = features.featureId ;
this.featureKey = features.featureKey;
this.featureCode = features.featureCode;
}
/*...*/
}
You can see how that implementation would actually work, here:
public class BigAssFields {
/* ... */
static public void main(String ... args){
BigAssFields bLike = new BigAssFields();
VehicleFeature vehFeatures = new VehicleFeature("what", "the actual", "Feature");
TechSpecs bigTechSpecs = bLike.addFeatures(TechSpecs.class, vehFeatures);
}
/* ... */
}

Related

Send a serializable class through a Socket

I'm trying to send an ArrayList of Email to a server through a Socket, but when I try to fo this I get a NotSerializableException: javafx.beans.property.SimpleObjectProperty I read on the forum that I need to implement Serializable into may Email class, which is this:
public class Email implements Serializable {
private final IntegerProperty id = new SimpleIntegerProperty();
public final IntegerProperty IDProperty() {
return this.id;
}
public final Integer getID() {
return this.IDProperty().get();
}
public final void setID(final Integer id) {
this.IDProperty().set(id);
}
private final StringProperty mittente = new SimpleStringProperty();
public final StringProperty MittenteProperty() {
return this.mittente;
}
public final String getMittente() {
return this.MittenteProperty().get();
}
public final void setMittente(final String mittente) {
this.MittenteProperty().set(mittente);
}
private final StringProperty destinatario = new SimpleStringProperty();
public final StringProperty DestinatarioProperty() {
return this.destinatario;
}
public final String getDestinatario() {
return this.DestinatarioProperty().get();
}
public final void setDestinatario(final String destinatario) {
this.DestinatarioProperty().set(destinatario);
}
private final StringProperty oggetto = new SimpleStringProperty();
public final StringProperty OggettoProperty() {
return this.oggetto;
}
public final String getOggetto() {
return this.OggettoProperty().get();
}
public final void setOggetto(final String oggetto) {
this.OggettoProperty().set(oggetto);
}
private final StringProperty testo = new SimpleStringProperty();
public final StringProperty TestoProperty() {
return this.testo;
}
public final String getTesto() {
return this.TestoProperty().get();
}
public final void setTesto(final String testo) {
this.TestoProperty().set(testo);
}
private final ObjectProperty<Date> data = new SimpleObjectProperty<Date>();
public final ObjectProperty<Date> DataProperty() {
return this.data;
}
public final Date getData() {
return this.data.get();
}
public final void setData(final Date data) {
this.data.set(data);
}
public Email (int id, String mittente, String destinatario, String oggetto, String testo, Date data) {
setID(id);
setMittente(mittente);
setDestinatario(destinatario);
setOggetto(oggetto);
setTesto(testo);
setData(data);
}
}
This is the part where I try to send it:
ObjectOutputStream objectOutput = new ObjectOutputStream(incoming.getOutputStream());
objectOutput.writeObject(arr);
But nothing changed. What should I modify?
You should implement writeObject and readObject methods in your Email class because it requires some special handling (it has non-serializable fields).
Also in readObject you need some work to initialize final fields.
At the end these two methods shold look like this:
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
out.writeInt(getID());
out.writeUTF(getMittente());
out.writeUTF(getDestinatario());
out.writeUTF(getOggetto());
out.writeUTF(getTesto());
out.writeObject(getData());
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
try {
Field field = this.getClass().getDeclaredField("id");
field.setAccessible(true);
field.set(this, new SimpleIntegerProperty());
field = this.getClass().getDeclaredField("mittente");
field.setAccessible(true);
field.set(this, new SimpleStringProperty());
field = this.getClass().getDeclaredField("destinatario");
field.setAccessible(true);
field.set(this, new SimpleStringProperty());
field = this.getClass().getDeclaredField("oggetto");
field.setAccessible(true);
field.set(this, new SimpleStringProperty());
field = this.getClass().getDeclaredField("testo");
field.setAccessible(true);
field.set(this, new SimpleStringProperty());
field = this.getClass().getDeclaredField("data");
field.setAccessible(true);
field.set(this, new SimpleObjectProperty<Date>());
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new IOException(e);
}
setID(in.readInt());
setMittente(in.readUTF());
setDestinatario(in.readUTF());
setOggetto(in.readUTF());
setTesto(in.readUTF());
setData((Date)in.readObject());
}

Iterating in a list and deleting contents of an object in Java

I have an Arraylist named deleteFields.
I have an Object named mergedDiffSRO.
I have to delete all the fields of mergedDiffSRO which are present in deleteFields.
LeadDetailsSRO mergedDiffSRO = new LeadDetailsSRO();
public class LeadDetailsSRO{
private String emailId;
private String emailByCompany;
private int level;
private LeadObjects leadobj;
private String alternateNumber;
private String languagePreference;
private String kycName;
private String businessAs;
private String aadharName;
private String panName;
private String ovdName;
private String kycStatus;
private String aadhaarStatus;
private String panStatus;
private Set<String> ownershipTypeSet;
private String empId;
private String designation;
private Boolean nameMatchSuccess = null;
private String isSIMandatory;
}
List<String> deleteFields = new ArrayList<String>();
deleteFields.add("businessAs");
deleteFields.add("empId");
deleteFields.add("designation");
deleteFields.add("emailByCompany");
deleteFields.add("level");
deleteFields.add("ovdName");
How do i proceed with the same?
Is reflection to be used for the same?
Please suggest some way out with proper code in JAVA.
You can do it with reflection. But that's ugly, slow and error-prone. So, here it is:
public void deleteFieldsByName(LeadDetailsSRO details, List<String> fieldNames) throws Exception {
for (String fieldName : fieldNames) {
Field field = LeadDetailsSRO.class.getDeclaredField(fieldName);
// this is usually not allowed at production settings
field.setAccessible(true);
Class fieldType = field.getType();
// the following if-else is ugly.
// But that's what we can do. We have to differentiate by classes.
if (fieldType.equals(String.class)) {
field.set(details, null);
} else if (fieldType.equals(Set.class)) {
field.set(details, new HashSet<>());
} else if (fieldType.toString().equals("int")) {
field.set(details, 0);
}
}
I suggest that you look for other kind of solutions.
Update
We can do it without reflection too. This is still ugly and error-prone. But at least, it's fast and it will work in prod environments too:
public class LeadDetailsSRO {
private String emailId;
private String emailByCompany;
private int level;
private String alternateNumber;
private String languagePreference;
private String kycName;
private String businessAs;
private String aadharName;
private String panName;
private String ovdName;
private String kycStatus;
private String aadhaarStatus;
private String panStatus;
private Set<String> ownershipTypeSet;
private String empId;
private String designation;
private Boolean nameMatchSuccess = null;
private String isSIMandatory;
public void deleteFields(List<String> fields) {
for (String fieldName : fields) {
switch (fieldName) {
case "emailId":
this.emailId = null;
break;
case "emailByCompany":
this.emailByCompany = null;
break;
// ...
}
}
}
}

How do I set limited generic return type

Taking the following 2 objects, I cant figure out how to make the following work.
public final *Generic SubType* getInfo(){
...
}
First the class I am working with
public class ResultEntry<Type extends ResultType>{
private final Type mType;
private final String mLabel;
private final String mInfo;
private ResultEntry(final Type t, final String label, final String info){
mType = t;
mLabel = label;
mInfo = info;
}
public static ResultEntry<ResultType> newInstance(final String label, final Number info){
return new ResultEntry<>(ResultType.NUMBER, label, info.toString());
}
public static ResultEntry<ResultType> newInstance(final String label, final Boolean info){
return new ResultEntry<>(ResultType.NUMBER, label, info.toString());
}
public static ResultEntry<ResultType> newInstance(final String label, final String info){
return new ResultEntry<>(ResultType.NUMBER, label, info);
}
public final ResultType getType(){
return mType;
}
public final String getLabel(){
return mLabel;
}
public final *Generic SybType* getInfo(){
}
}
And then enum ResultType
public enum ResultType {
STRING ("STRING"),
BOOLEAN ("BOOLEAN"),
NUMBER ("NUMBER");
private final String s;
ResultType(final String string){
s = string;
}
public final boolean isString(){
return s.equals(STRING.s);
}
public final boolean isBoolean(){
return s.equals(BOOLEAN.s);
}
public final boolean isNumber(){
return s.equals(NUMBER.s);
}
}
What I would like to do is have a way to check what mType is (String, Boolean, or Number) and then return that actual object. Something like,
public final *Generic SubType* getInfo(){
if(mType.isString()) return new String();
if(mType.isNumber()) return new Number();
if(mType.isBoolean()) return new Boolean();
}
Though obviously I would have actual information to pass back instead.
But I dont know if that is possible, and if so, I don't know how I would go about doing it. It does appear that Android is able to do it via AsyncTask.
For reference, I found most of this from This Question
I would suggest you do it like this, which doesn't convert the info values to String, i.e. mInfo is Object, not String.
public class ResultEntry<R> {
private final ResultType mType;
private final String mLabel;
private final Object mInfo;
private ResultEntry(final ResultType t, final String label, final Object info) {
this.mType = t;
this.mLabel = label;
this.mInfo = info;
}
public static ResultEntry<Number> newInstance(final String label, final Number info) {
return new ResultEntry<>(ResultType.NUMBER, label, info);
}
public static ResultEntry<Boolean> newInstance(final String label, final Boolean info) {
return new ResultEntry<>(ResultType.BOOLEAN, label, info);
}
public static ResultEntry<String> newInstance(final String label, final String info) {
return new ResultEntry<>(ResultType.STRING, label, info);
}
public final ResultType getType() {
return this.mType;
}
public final String getLabel() {
return this.mLabel;
}
#SuppressWarnings("unchecked")
public final R getInfo() {
return (R) this.mInfo;
}
}
Then you use it like this:
ResultEntry<Number> numEntry = ResultEntry.newInstance("", 5);
ResultEntry<Boolean> boolEntry = ResultEntry.newInstance("", true);
ResultEntry<String> strEntry = ResultEntry.newInstance("", "Foo");
Number numInfo = numEntry.getInfo();
Boolean boolInfo = boolEntry.getInfo();
String strInfo = strEntry.getInfo();

Can Orika map nested collections?

I would like to map a field with nested collection using Orika library. My field in class is defined as:
private final List<List<Pojo>> list = new LinkedList<List<Pojo>>();
Pojo is a simple POJO class. Unfortunately I've got a MappingException caused by NullPointerException in Orika's internal logic.
Did I do something in wrong way? Maybe I need to use Custom Mapping feature?
EDIT:
Here is my code:
public class Pojo {
private int field;
public int getField() {
return field;
}
public void setField(final int field) {
this.field = field;
}
}
public class Source {
private final List> list = new LinkedList>();
public List<List<Pojo>> getList() {
return list;
}
}
public class Destination {
private final List> listDest = new LinkedList>();
public List<List<Pojo>> getListDest() {
return listDest;
}
}
public class Main {
public static void main(final String[] args) {
final MapperFactory factory = new DefaultMapperFactory.Builder().build();
factory.classMap(Source.class, Destination.class).field("list", "listDest").byDefault().register();
final Source src = new Source();
final LinkedList<Pojo> nestedList = new LinkedList<Pojo>();
final Pojo pojo = new Pojo();
pojo.setField(8978);
nestedList.add(pojo);
src.getList().add(nestedList);
final MapperFacade facade = factory.getMapperFacade();
final Destination dest = facade.map(src, Destination.class);
System.out.println(dest.getListDest().get(0).get(0).getField());
}
}
Execution above code results this Exception:
Exception in thread "main" ma.glasnost.orika.MappingException: Error encountered while mapping for the following inputs:
rawSource=com.bbh.nested.Source#39185ce6
sourceClass=class com.bbh.nested.Source
destinationClass=class com.bbh.nested.Destination
You can see this Example:
public class ShopEntity {
private Long id;
private String name;
private String logo;
private String url;
private ProductCategory mainCategory;
private Set<ShopRel> shopRels = new HashSet<>(0);
private Account account;
// Assume getter/setter
}
public class ProductCategory extends BaseEntity {
private Long id;
private String name;
// Assume getter/setter
}
public class ShopRel {
private Long id;
private SaleChannel saleChannel;
private Boolean enabled;
// Assume getter/setter
}
public class SaleChannel {
private Long id;
private String name;
private String image;
private String description;
private Boolean active;
// Assume getter/setter
}
public class ShopDto {
private Long id;
private String name;
private String logo;
private String url;
private Long mainCategory;
private Set<ShopRelDto> shopRelDtos = new HashSet<ShopRelDto>();
// Assume getter/setter
}
public class ShopRelDto {
private Long channelId;
private String name;
private Boolean enabled;
// Assume getter/setter
}
public class MapperUtils {
private static final MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
private static final MapperFacade mapper = mapperFactory.getMapperFacade();
static {
mapperFactory.classMap(ShopEntity.class, ShopDto.class)
.field("mainCategory.id", "mainCategory")
.fieldMap("shopRels", "shopRelDtos").aElementType(ShopRel.class).bElementType(ShopRelDto.class).add()
.register();
mapperFactory.classMap(ShopRel.class, ShopRelDto.class)
.field("saleChannel.id", "channelId")
.field("saleChannel.name", "name")
.field("enabled", "enabled")
.register();
}
public static final void map(Object source, Object distance) {
mapper.map(source, distance);
}
public static final <T> T map(Object source, Class<T> destinationClass){
return mapper.map(source, destinationClass);
}
public static void main(String[] args) {
ShopEntity shop = new ShopEntity();
shop.setId(1L);
shop.setName("ABC");
ProductCategory productCategory =new ProductCategory();
productCategory.setId(10L);
shop.setMainCategory(productCategory);
Set<ShopRel> shopRels = new HashSet<>(0);
ShopSaleChannelRel channelRel = new ShopSaleChannelRel();
channelRel.setId(1L);
channelRel.setEnabled(true);
SaleChannel saleChannel = new SaleChannel();
saleChannel.setId(1L);
saleChannel.setName("Channel1");
channelRel.setSaleChannel(saleChannel);
shopRels.add(channelRel);
shop.setShopRels(shopRels);
ShopDto shopDto = map(shop, ShopDto.class);
System.out.println(shopDto);
}
}
It may need a custom mapping via customize if there is lot of cases like this you can extend Orika via Specifications to support this use case

Merge two Arrays of different objects into one Array/collection

I'm facing this task:
I have class A and class B. These two classes are different but almost the same.
I need to somehow merge them into 1 Single array of objects so I will be able to use them later in a list that combines both classes.
Class A:
public class Followers {
private String request_id;
private String number_sender;
private String state;
public String getRequest_id() {
return request_id;
}
public String getNumber_sender() {
return number_sender;
}
public String getState() {
return state;
}
}
Class B:
public class Following {
private String name;
private String state;
private String request_id;
public String getRequest_id() {
return request_id;
}
public String getName() {
return name;
}
public String getState() {
return state;
}
}
I've tried doing this next move:
Object[] obj1 = (Object[]) followers;
Object[] obj2 = (Object[]) followings;
Object[] completeArray = ArrayUtils.addAll(obj1, obj2);
Where followers and followings are both arrays of the corresponding classes. Then in my list adapter I use:
if (values[currentItem] instanceof Followers) { BLA BLA BLA}
else if (values[currentItem] instanceof Following) { BLA BLA BLA}
But I get this exception:
Caused by: java.lang.ArrayStoreException: source[0] of type json.objects.Following cannot be stored in destination array of type json.objects.Followers[]
What will be the best way to merge two arrays of different objects into one array?
Will just implementing the same interface between them do the job and then they will basically be in an array of the interface type?
what other ways do you recommend?
Try this
Object[] completeArray = new Object[0];
completeArray = ArrayUtils.addAll(completeArray, obj1);
completeArray = ArrayUtils.addAll(completeArray, obj2);
If you make both classes implement a common interface you can manipulate arrays/lists of them as if they contains instances of the interface.
public interface Follow {
public String getRequest_id();
public String getState();
}
public class Follower implements Follow {
private String request_id;
private String number_sender;
private String state;
public String getRequest_id() {
return request_id;
}
public String getNumber_sender() {
return number_sender;
}
public String getState() {
return state;
}
}
public class Following implements Follow {
private String name;
private String state;
private String request_id;
public String getRequest_id() {
return request_id;
}
public String getName() {
return name;
}
public String getState() {
return state;
}
}
public void test() {
List<Follow> all = new ArrayList<>();
all.add(new Following());
all.add(new Follower());
for ( Follow f : all ) {
String id = f.getRequest_id();
String state = f.getState();
}
}
Alternatively you could put them in a hierarchy:
public class Entity {
private String request_id;
private String state;
public String getRequest_id() {
return request_id;
}
public String getState() {
return state;
}
}
public class Follower extends Entity {
private String number_sender;
public String getNumber_sender() {
return number_sender;
}
}
public class Following extends Entity {
private String name;
public String getName() {
return name;
}
}
public void test() {
List<Entity> all = new ArrayList<>();
all.add(new Following());
all.add(new Follower());
for ( Entity f : all ) {
String id = f.getRequest_id();
String state = f.getState();
}
}
Or you could make the extra fields into attributes.
enum Attribute {
Follows,
Followed;
}
public static class Entity {
private String request_id;
private String state;
EnumMap<Attribute, String> attributes = new EnumMap<>(Attribute.class);
public String getRequest_id() {
return request_id;
}
public String getState() {
return state;
}
// Factory to make entities.
static Entity make(Attribute attribute, String value) {
Entity e = new Entity();
e.attributes.put(attribute, value);
return e;
}
}
public void test() {
List<Entity> all = new ArrayList<>();
all.add(Entity.make(Attribute.Follows, "Fred"));
all.add(Entity.make(Attribute.Followed, "Gill"));
for (Entity f : all) {
String id = f.getRequest_id();
String state = f.getState();
}
}
There are an infinite number of possibilities.
USE concat
var combined= obj1.concat(obj2); // Merges both arrays
Try this.
private Object[] appendObj(Object[] obj, Object newObj) {
ArrayList<Object> temp = new ArrayList<Object>(Arrays.asList(obj));
temp.add(newObj);
return temp.toArray();
}

Categories