Java: Passing different custom objects that implement same interface to method [duplicate] - java

This question already has answers here:
Java collections covariance problem
(3 answers)
Closed 6 years ago.
I'm trying to write a general method that writes different types of Java Beans (so List<JavaBean>) to a file. I'm currently constructing a FileManager utility class. Each Java Bean implements the same interface. Here's an example of what I'm trying to do.
public interface Data { method declarations }
public class RecipeData implements Data { class stuff goes here }
public class DemographicData implements Data { class stuff goes here }
final public class FileManager {
public static void writeToCsvFile(String filename, List<Data> data) { file writing logic goes here }
}
I want to be able to pass a List<RecipeData> and a List<DemographicData> to this method. Obviously what I have does not work.
It doesn't seem I can even do the following:
List<Data> data = new ArrayList<RecipeData>();
How would this normally be done? In Swift I might use the as? keyword to cast it to the correct type.
**************EDIT**************
Just to preface I'm using the SuperCSV library to assist in parsing rows into a Java Bean and I am using the accepted answer below for the method definition. So I have the following code:
Data dataset;
while((dataset = beanReader.read(Data.class, nameMappings, processors)) != null ) {
container.add(dataset);
}
I get the following error:
The method add(capture#1-of ? extends Data) in the type List is not applicable for the arguments (Data)
dataset needs to be either type RecipeData or DemographicData for this to work I'd assume. Is there an easy way to fix this so that it is flexible if I add more Beans in the future?

final public class FileManager {
public static void writeToCsvFile(String filename, List<? extends Data> data) { file writing logic goes here }
}
additionally, you can declare
List<Data> data = new ArrayList<RecipeData>();
as
List<Data> data = new ArrayList<Data>();
or, in Java 7,
List<Data> data = new ArrayList<>();
and just populate it with RecipeData, since either way you are losing the information that this List is to contain only RecipeData

Related

Iterate Fields of Fields continuously with reflection

Please avoid giving answers in Kotlin only and higher than Android 21.
I'm trying to build an API parser that makes use of class hierarchy logic to represent the API hierarchy itself. With this structure I am able to parse the API in an uncomplicated fashion and I was able to achieve this already, but I'd like to improve it further.
I'll begin explaining what I already have implemented.
This is an example URL that my app will receive via GET, parse and dispatch internally:
http://www.example.com/news/article/1105
In the app the base domain is irrelevant, but what comes after is the API structure.
In this case we have a mixture of commands and variables:
news (command)
article (command)
1105 (variable)
To establish what is a command and what is a variable I built the following class structures:
public class API {
public static final News extends AbstractNews {}
}
public class AbstractNews {
public static final Article extends AbstractArticle {}
}
public class Article {
public static void GET(String articleId) {
// ...
}
}
And I iterate through each class after splitting the URL while matching each command to each class (or subclass) starting from the API class. Until I reach the end of the split URL any matches that fail are stored in a separate list as variables.
The process is as follows for the example provided above:
Split URL each forward slash (ignoring the base domain)
/news/article/1105
List<String> stringList = [
news,
article,
1105
];
Iterate each item in the split list and match agains the API structured classes (the following is just a sample example, it is not 100% of what I currently have implemtend):
List<String> variableList = new ArrayList<>();
Class lastClass = API.class;
for (String stringItem : stringList) {
if ((lastClass = classHasSubClass(lastClass, stringItem)) != null) {
continue;
}
variableList.add(stringItem);
}
Once the end of the list is reached I check if the last class contains the request method (in this case GET) and invoke along with the variable list.
Like I said before this is working perfectly fine, but it leaves every class directly exposed and as a result they can be accessed directly and incorrectly by anyone else working on the project, so I am trying to make the hierarchy more contained.
I want to keep the ability to access the methods via hierarchy as well, so the following can still be possible:
API.News.Article.GET(42334);
While at the same time I don't want it to be possible to do the following as well:
AbstractArticle.GET(42334);
I have tried making each subclass into a class instance field instead
public class API {
// this one is static on purpose to avoid having to instantiate
// the API class before accessing its fields
public static final AbstractNews News = new AbstractNews();
}
public class AbstractNews {
public final AbstractArticle Article = new AbstractArticle();
}
public class Article {
public void GET(String articleId) {
// ...
}
}
This works well for the two points I wanted to achieve before, however I am not able to find a way to iterate the class fields in a way that allows me to invoke the final methods correctly.
For the previous logic all I needed to iterate was the following:
private static Class classHasSubClass(Class<?> currentClass, String fieldName) {
Class[] classes;
classes = currentClass.getClasses();
for (final Class classItem : classes) {
if (classItem.getSimpleName().toLowerCase().equals(fieldName)) {
return classItem;
}
}
return null;
}
But for the second logic attempt with fields I was not able to invoke the final method correctly, probably because the resulting logic was in fact trying to do the following:
AbstractArticle.GET(42334);
Instead of
API.News.Article.GET(42334);
I suspect it is because the first parameter of the invoke method can no longer be null like I was doing before and has to be the correct equivalent of API.News.Article.GET(42334);
Is there a way to make this work or is there a better/different way of doing this?
I discovered that I was on the right path with the instance fields, but was missing part of the necessary information to invoke the method correctly at the end.
When iterating the fields I was only using the Class of each field, which was working perfectly fine before with the static class references since those weren't instances, but now it requires the instance of the field in order to work correctly.
In the end the iterating method used in place of classHasSubClass that got this to work is as follows:
private static Object getFieldClass(Class<?> currentClass, Object currentObject, final String fieldName) {
Field[] fieldList;
fieldList = currentClass.getDeclaredFields();
for (final Field field : fieldList) {
if (field.getName().toLowerCase().equals(fieldName)) {
try {
return field.get(currentObject);
} catch (IllegalAccessException e) {
e.printStackTrace();
break;
}
}
}
return null;
}
With this I always keep an instance object reference to the final field that I want to invoke to pass as the 1st parameter (someMethod.invoke(objectInstance);) instead of null.

Interface to enforce generic static method in Java

I have a Java class Model which models some data from my remote database. I want all data models in my project to be able to supply a builder from a Map<String, Object> instance (in practice, I'm working with SnapshotParser<Model> parsers with Firestore, but I'll just call getData() in every model). This should look something like:
public class Model {
private String name;
public Model(String name) { this.name = name; }
public static SnapshotParser<Model> getDocParser() {
return docSnapshot -> {
Map<String, Object> data = docSnapshot.getData();
return new Model(data.getOrDefault("name", "John Doe"));
};
}
}
Note that I'll have several models (Model2, Model3...) which will also be required to provide such an interface. To enforce this behavior, I created a DocParserSupplier generic class for my model classes to implement:
public interface DocParserSupplier<T> {
static SnapshotParser<T> getDocParser();
}
This doesn't work for two reasons (as Android Studio informs me):
static methods of interfaces must have a default implementation. I can't do that without knowing T.
I get the "T cannot be referenced in static context" error.
If remove the static keyword from the above interface, I can do what I want but it would require I create an actual instance of the Model to get the parser. It would work but it makes more sense if the method is static.
Is there a Java way to do what I want?
EDIT: My specific use case is in matching RecyclerViews to documents in my database. Constructing the FirestoreRecyclerOptions object requires a parser to convert key-value data to a Model:
FirestoreRecyclerOptions<Model1> fro1 = new FirestoreRecyclerOptions.Builder<Model1>()
.setQuery(query1, Model1.getDocParser())
.build();
FirestoreRecyclerOptions<Model2> fro2 = new FirestoreRecyclerOptions.Builder<Model2>()
.setQuery(query2, Model2.getDocParser())
.build();
Interfaces enforce behavior of instances, so that references to any object which has that behavior can be passed around in a type-safe way. Static methods on the other hand, don't belong to any particular instance of an object; the class name is essentially just a namespace. If you want to enforce behavior, you will have to create an instance somewhere (or use reflection, if it is absolutely necessary to ensure a class has a particular static method).
Unless this system is going to be opened up for extension, where others can define their own models, I would say ditch the DocParserSupplier interface altogether and call the static methods exactly as you are now, or factor them out into a factory interface + implementation. The factory option is nice because you can replace the production implementation with a fake implementation that returns dummy parsers for tests.
Edit: Doc Parser Factory
public interface DocParserFactory {
SnapshotParser<Model1> getModel1Parser();
SnapshotParser<Model2> getModel2Parser();
...
SnapshotParser<Model1> getModelNParser();
}
...
// The implementation of each getModelXParser method
class DocParserFactoryImpl {
SnapshotParser<Model1> getModel1Parser() {
return docSnapshot -> {
Map<String, Object> data = docSnapshot.getData();
return new Model(data.getOrDefault("name", "John Doe"))};
}
...
}
...
private DocParserFactory docParserFactory;
// You can inject either the real instance (DocParserFactoryImpl) or a
// test instance which returns dummy parsers with predicable results
// when you construct this object.
public ThisObject(DocParserFactory docParserFactory) {
this.docParserFactory = docParserFactory;
}
...
// Your code
public void someMethod() {
...
FirestoreRecyclerOptions<Model1> fro1 = new
FirestoreRecyclerOptions.Builder<Model1>()
.setQuery(query1, docParserFactory.getModel1Parser())
.build();
FirestoreRecyclerOptions<Model2> fro2 = new
FirestoreRecyclerOptions.Builder<Model2>()
.setQuery(query2, docParserFactory.getModel2Parser())
.build();
...
}
It's not so much to do with static or non-static, as it is with the fact that you cannot create an instance of a generic object without passing the type parameter(s) one way or another. In fact, I answered a similar question a few days ago, when somebody wanted to use enums to get the required builder.
In short, you cannot write a method <T extends AbstractBuilder> T builder(final SomeNonGenericObject object) (or, in this case, <T extends AbstractBuilder> T builder()) without passing T in some form. Even though it will make sense at runtime, the compiler can't figure out what generic type to use if you don't tell it which one it is.
In Java 8, you can solve this elegantly with method references. I don't know much about Android, but I believe you're still on Java 6 there, so this wouldn't work.
Anyway, you can have something like the following:
public <T extends AbstractBuilder> T builder(final Supplier<T> object) {
return supplier.get();
}
final Supplier<AbstractBuilder> model1BuilderSupplier = Model1Builder::new;
builder(model1BuilerSupplier)
.setQuery(query1, Model1.getDocParser())
.build();
It's not exactly what you want, but the way you're trying to go about it will not work.

Is this an example of anti-pattern?

Me and one of my colleague were trying to solve the following problem:
Lets take an example of class A
One of my colleagues was facing problem of extracting one particular property from A.
Fetching one property from One particular class (in this case A) is easy. but lets
assume that you have multiple classes (A1, A2...) and you want to fetch one
particular property from the collection of these classes with more and more reusability of code.
for example
public class A {
private String name;
.
.
.
}
List<String> listOfNames = createNameList(listOfAInstances);
createNameList() method would be like following:
List<String> tempList = new ArrayList<>();
for(A a : listOfAInstances) {
tempList.add(a.getName());
}
return tempList;
now if there are multiple classes I have to do this for each class and different properties.
I suggested two approaches:
Reflection based approach.
Create an interface called "PropertyExtractable" and put a method in it called "extractProperty" in it.
As shown below:
interface PropertyExtractable {
Object extractProperty();
}
public class A implements PropertyExtractable {
private String name;
.
.
.
public Object extractProperty() {
return this.name;
}
}
For this I can write some utility method which then can be used everywhere i.e.
public Object getPropertiesOfPropertyExtractable(PropertyExtractable prExtractable) {
return prExtractable.extractProperty();
}
This was the background, one other colleague of mine had different opinion about 2nd approach, he told me it seems like anti-pattern. He tried to explain to me but I didn't get it entirely so and hence I am asking here.
I am trying to compare this example with the Comparator interface in Java. Like java allows us to use Comparator on any of the custom object class and allows us to define the logic for comparison then why can't I define the logic for extraction
Further more interfaces can be used in this way, then why shouldn't we use it
I want to know is this approach an anti-pattern? why?
You can place extracting code in separate method and reuse it:
class A {
private String name;
public String getName() {
return name;
}
}
class B {
private String surname;
public String getSurname() {
return surname;
}
}
public class SomeClass {
private <T> List<String> extractFields(List<T> list, Function<T, String> extractorFunction) {
return list.stream().map(extractorFunction).collect(Collectors.toList());
}
public void someMethod() {
List<A> listOfInstancesA = new ArrayList<>();
List<B> listOfInstancesB = new ArrayList<>();
// fill lists
List<String> fieldsA = extractFields(listOfInstancesA, A::getName);
List<String> fieldsB = extractFields(listOfInstancesB, B::getSurname);
}
}
The situation you describe is working with a legacy system which you don't want to change.
Since if you weren't you'd introduce an interface for the common properties (like your example for the Comparator interface). You introduced an interface without a meaning which may be an anti-pattern since you actually need a functional interface: PropertyExtractable vs. NamedObject=> has a method: String getName()).
If you want to implement Reflection, then your interface may be correct but I don't see it (e.g. in your case you already have Reflection built in into Java).
Usually you use the Adapter pattern to get a property/method from an object which doesn't implement the requested interface.

How to create different objects depending on the parameter passed? [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 6 years ago.
I have a use-case like this:
Based on the parameter passed - I have to create an object corresponding to it but the underlying functionality remains same.
public void selectType ()
{
String type = "ABC";
publishType(type);
}
public void publishType(String type)
{
if (type.equals("ABC"))
ABCtype publishObject = new ABCtype();
if (type.equals("XYZ"))
XYZtype publishObject = new XYZtype();
publishObject.setfunctionality();
}
What is a better way to approach this?
Which design pattern does it fall in?
Another doubt I have is - how to initialize publishObject?
It gives an error like this.
but the underlying functionality remains same
you maybe consider design suing interfaces..
Do some nice Archi- Design like:
define an interface, and 2 classes that implement the interface, then
declare an object foo and initialize it according to the parameter..
Example:
interface IObject{
//methods here
}
class A implements IObject{}
class B implements IObject{}
public void selectType ()
{
IObject foo = getObject(1);
}
public IObject getObject(int type){
if (type ==1){
return new A();
}else{
return new B();
}
}

Serialize Java functions in Java 8 [duplicate]

This question already has answers here:
How to serialize a lambda?
(5 answers)
Closed 6 years ago.
I am trying to create a class which models a program stack. Is it possible to make this class serializable? I want to be able to use this as Akka messages. Thanks!
public class ProgramStack<T>{
public final Queue<UnaryOperator<T>> programStack;
private T context;
ProgramStack(Queue<UnaryOperator<T>> programStack, T context) {
this.programStack = programStack;
this.context = context;
}
public void next() {
UnaryOperator function = programStack.poll();
function.apply(context);
}
public boolean hasNext() {
return !programStack.isEmpty();
}
}
For one you don't serialize methods you serialize objects that have behaviors. Anyway in order to be able to serialize this you must implement Serializable. All of it's member must do this. If you look at the doc https://docs.oracle.com/javase/8/docs/api/java/util/Queue.html Queue does not implement Serializable so make sure what ever object implements Queue is serializable. I don't know what T is must but that must also implement Serializable in order to serialize your object of type ProgramStack.
import java.io.Serializable;
public class ProgramStack<T> implements Serializable {
// etc etc
}

Categories

Resources