Generic methods to read/write to file all classes that extend X - java

sorry if this is a duplicate question, but I'm getting kind of desperate to solve a problem for a school project (due date tomorrow).
I'm very new to Java and this project involves storing data from certain objects to a local repository and also reading the data from the repo.
The repository handler class is in one package and the objects are in another.
My problem is that I don't know how to make generic methods in the handler to be able to read and write any object that extends X.
For example, let's say I have Fruit.
Apple extends Fruit.
Orange extends Fruit.
Both have their own unique attributes that I need to write/read to/from a file.
I wanted to have a method like
ArrayList repo_reader(String filepath)
That reads from a file and returns Apples and Oranges.
The only way that I know how to do this is having a field in the file stating which type of fruit it is, reading it and throwing it to a switch case like
switch (fruit_type){
case "Orange":
Orange orange = new Orange(); orange.setOrangeSpecificAttribute("ble");
FruitBasket.add(orange);
case "Apple":
Apple apple = new Apple(); apple.setAppleSpecificAttribute("bla");
FruitBasket.add(apple);
But then the method wouldn't be generic. Everytime that someone creates a new Fruit class, they would have to also change the repo_handler methods accordingly. The same would also happen with the writing method.
I could have the Fruit classes all implement their own method to write and read, but I don't want that. I want repo_handler class to deal with all the file reading and writing.
Again, sorry if it's a stupid question, and thanks for your guys' attention!
Btw, it's a CSV file, forgot to mention.

You may want to have different readers/factories dependending on the contents of some String. That is, the String acts as identifier for the reader/factory to use.
You can use a map to map identifiers (keys) to readers/factories (values). As the latter must be registered, I'd use the service loader mechanism as described in ServiceLoader, and iterate over all services to register them in this map.
Having this, you can look up the needed reader/factory in the map and use it to read/create new Fruit instances.
Step #1: Service Provider Interface
package com.mycompany.fruit;
public interface FruitFactory {
String getIdentifier();
Fruit createFruit(String[] attributes); // change params to your needs
}
Step #2: Service implementation
package com.mycompany.fruit;
public class AppleFactory implements FruitFactory {
public String getIdentifier() { return "Apple"; }
public Fruit createFruit(String[] attributes) {
Apple apple = new Apple();
apple.setCommonAttribute(attributes[1]);
apple.setSpecificAttribute(attributes[2]);
// ...
return apple;
}
}
Step #3: Register factories
Put a file com.mycompany.fruit.FruitFactory in META-INF/services. Put the fully qualified class name of each implementation of FruitFactory on separate lines in this file. For example:
com.mycompany.fruit.AppleFactory
com.mycompany.fruit.OrangeFactory
...
Step #4: Load the services and use them
public class MyFruitReader {
Map<String, FruitFactory> factories;
public MyFruitReader(...) {
ServiceLoader<FruitFactory> loader = new ServiceLoader(FruitFactory.class);
for (FruitFactory factory : loader) {
factories.put(factory.getIdentifier(), factory);
}
// usage
private Fruit getFruit(String[] row) {
String fruitType = row[0];
FruitFactory factory = factories.get(fruitType);
if (factory == null) {
return null;
}
return factory.createFruit(row);
}
// read the CSV file and call getFruit()
// ...
Keep in mind, that this are just sketches to provide a rough overview of this topic. You'll have to adapt it to your needs, add exception handling, fix errors, and so on.

Related

Java Method construction for repeated structure with small changes

I'm not sure if there's a pattern that covers this question, but here goes. In writing a method to call an analytical algorithm (such as a parser or calculation implementation), there is quite a large amount of code to read a source, apply the algorithm, then convert the results to something useful. Basically theres 20-30 lines of code and one algorithm/parser/tokenizer that changes quite often.
So.... my options that I see so far are:
Create a new method for each algorithm (ugly due to repetition)
Create a single method and pass in the algorithm as a parameter, then use a case or if/then to select the algorithm (this gets messy because I have to hard code my algorithm choices.
Create a separate initialization or setting of the algorithm and then check to see if its initialized in the method (which still is ugly, because somewhere else I have a hard-coded list of different algorithm choices in my selection method).
Is there a neat trick or general method construction programming pattern to solve this?
Thanks in advance.
--Edit--
To remove some of the abstraction of this question, here is a prototype of what I am talking about. So really only the implementation of the tokenizer changes.
pubic void tokenizeData(Filename datablob){
// convert filename
// open file
// handle file errors
// other code
// assign desired tokenizer
tokenizer = new TokenizerImplementation (or some other variation);
tokenizedData = tokenizer( cleansedData );
// parsing and collection code
// more error processing code
// cleanup code
}
I'd also go personnally for some combination of Interface and Abstract + Template Method as suggested by #Lucas Oliveira but for your very problem of selecting the appropriate Tokenizer implementation you may also need a Factory(pattern) to dynamically load another Tokenizer impl. based on the factory context or parameters without changing the content of your template method tokenizeData().
Example.1 a classic parametered Factory:
public class TokenizerFactory
{
private static final Logger logger = LoggerFactory.getLogger(TokenizerFactory.class);
private final int version;
public TokenizerFactory(int version) {
this.version = version;
}
public ITokenizer getInstance() {
switch(version) {
case 1: return new TokenizerV1();
case 2: return new TokenizerV2();
default: return new DefaultTokenizer();
}
}
}
Example.2 a dynamic class-loading static Factory (forgive me for the name):
public class TokenizerFactory
{
private static final Logger logger = LoggerFactory.getLogger(TokenizerFactory.class);
private TokenizerFactory() {}
// Here eg. ETokenizerType is a enum storing class associated to the type.
public static ITokenizer getInstance(ETokenizerType dtype) {
try {
return (ITokenizer)dtype.getClassVar().newInstance();
}
catch(Throwable ex) {
logger.error("Factory could not create an adequate instance of Tokenizer for dtype:{} !",dtype.name());
}
return new DefaultTokenizer();
}
}
You can define an interface for your Tokenizer(s) as:
public interface ITokenizer {
public void tokenizeData(Filename datablob);
}
... to be implemented by your abstract class AbstractTokenizer for which all subclasses (such as TokenizerV1 and TokenizerV2) will redefine only customized abstract method(s). Just like in the following example (based on #Lucas Oliveira proposal):
public abstract class AbstractTokenizer implements ITokenizer {
#Override
public void tokenizeData(Filename datablob) {
// convert filename
// open file
// handle file errors
// other code
tokenizedData = tokenizer( data );
// parsing and collection code
// more error processing code
// cleanup code
}
abstract TokenizedData tokenizer( Data cleansedData ); // << redef. by subclasses.
}
But it will transparent for you to use.
You can finally make use of your TokenizerFactory simply by providing a pre-configured one as argument to your main business methods or use them on-the-fly provided you own the parameter needed to parameterize it. So that the getInstance() call will return the exact Tokenizer you need able to ´tokenizeData()´.
Note: for highly parameterized factories, combining them with a Builder (pattern) is generally a life-saver.
Template Method seems what you are looking for.
It alows you to:
Define the skeleton of an algorithm in an operation, deferring some steps to client subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
Base class declares algorithm 'placeholders', and derived classes implement the placeholders.
This is done with an Abstract class. You should decide which steps of the algorithm are invariant (or standard), and which are variant (or customizable). The invariant steps are implemented in the abstract base class, while the variant steps can be supplied by oncrete derived classes.
In your case things will go like that:
abstract class AbstractTokenizer {
public void tokenizeData(final Object datablob) {
// convert filename
// open file
// handle file errors
// other code
tokenizedData = tokenizer( cleansedData );
// parsing and collection code
// more error processing code
// cleanup code
}
abstract TokenizedData tokenizer( Data cleansedData );
}

Bridge design pattern resulting in too many generics

I'm currently working on something for Minecraft, and I'm using the bridge pattern so my code can used with two separate server platforms, Sponge and Bukkit, with different (but somewhat similar) API's.
I have my core code, which depends only on abstractions of common things in Minecraft that I will need later on, such as players and items, as well as abstract factory and builder classes. The code for the specific server platforms will implement the factories and builders, and provide them as dependencies to the core code.
This has been working pretty well so far, but I'm running into an issue with abstractions that depend on each other. For example, I have adapters for Minecraft inventories and items that adapt from the server platform's item/inventory type, to my own abstract item/inventory type. Item and inventory objects will need to interact with each other, and since the core code doesn't know about the implementation, I've resorted to using generics. Here's some pseudocode:
interface Item<TBase> {
TBase getBase();
}
interface Inventory<TItem extends Item<*>> {
void addItem(TItem item);
}
The Item class adapts an item from the item type used by the server platform. The addItem() method implementations will use the getBase() method to add an instance of the server platform's item to an instance of the server platform's inventory. Overall, generics provide a solution to interaction between platform specific objects.
The problem I've been running into, however, is generics getting complicated as the size of the project increases. One reason is that classes that use items/inventories will require the same generics. For example, all players have an inventory:
interface Player<TItem extends Item<*>> {
Inventory<TItem> getInventory();
void giveItem(TItem item);
}
And something that uses a player needs to have generics, and so forth.
The second issue is that there are more interactions between instances than just these two, which could mean several generic parameters for an object, and therefore more generics on all the classes that use that object.
I suppose another solution would be not using generics at all, changing getBase() to return an Object type, and blindly cast, trusting that it's the correct type (which it will be).
I've put a ton of thought into this, and this is about the best I could come up with. I'm wondering if there are any other solutions that I'm missing, or any design patterns that might help with this problem.
If having the source would help, you can find it here:
https://github.com/BenWoodworth/FastCraft/tree/master/src/main/kotlin/net/benwoodworth/fastcraft
EDITED: Well, isn't this a bridge pattern?
public interface InventoryHolder
{
public void transfer(Player toPlayer, Item item);
}
then
public class Player implements InventoryHolder
{
List<Item> items;
public Item removeItem(Item item){
return items.remove(items.indexOf(item));
}
public void addItem(Item item) {
items.add(item);
}
public void transfer(Player toPlayer, Item item)
{
toPlayer.addItem(removeItem(item));
}
}
and
public class Item {}
so
public class PlayGame
{
public static void main(String... args) {
new PlayGame().run();
}
private void run() {
Player p1 = new Player();
Player p2 = new Player();
Item item = new Item();
p1.addItem(item);
// transfer
p1.transfer(p2, item);
}
}
This is my current solution. If you see any room for improvement, by all means, share your insights. Here's some of my source code, simplified, and written in Kotlin.
dependencies:
// An abstract class, to be used by objects adapting
// native implementations. Provides an unwrap method,
// to unwrap the adapted object.
abstract class Adapter(protected val base: Any) {
#Suppress("UNCHECKED_CAST")
fun <T> unwrap() = base as T
}
// Inventory adapter, extends Adapter
abstract class InventoryAdapter(baseInventory: Any) : Adapter(baseInventory)
// Player adapter, extends Adapter
abstract class PlayerAdapter(basePlayer: Any) : Adapter(basePlayer) {
abstract fun openInventory(inventory: InventoryAdapter)
}
Sponge implementation:
// Adapts Player (from the Sponge API)
class SpongePlayerAdapter(
protected val basePlayer: Player
): PlayerAdapter(basePlayer) {
override fun openInventory(inventory: InventoryAdapter) {
// The unwrap<T>() method inferences T as Sponge's
// Inventory type, from the openInventory parameter
basePlayer.openInventory(inventory.unwrap())
}
}
The need for generics has been removed, at the cost of type safety. PlayerAdapter.openInventory() can be called by passing in an InventoryAdapter object as a parameter. If the PlayerAdapter is a SpongePlayerAdapter, and the InventoryAdapter is a SpongeInventoryAdapter, then the unwrap() method will return a Sponge Inventory, and the inventory will be opened for the player as expected.
If a BukkitInventoryAdapter object were passed in, for example, a casting exception will be thrown at runtime, since the unwrap() method will try to cast a Bukkit Inventory to a Sponge Inventory. This isn't a big issue, and shouldn't cause errors as long as dependencies are injected correctly.
The proper "solution" is to use a language that has a better type system than Java/Kotlin, unfortunately.
There's a type system feature exactly for this use case - called abstract type members or associated types or existential types (depending on the language).
This feature "hides" the generic parameter inside the concrete class, meaning that it does not bloat the generic parameter lists (the trade-off is that the type is hidden from the outside world when referred to via the base interface in the declarer/caller - it can only be accessed via the concrete class type itself).
As an example in Scala (refer to https://docs.scala-lang.org/tour/abstract-type-members.html):
// Interfaces
trait ItemBridge {
type TBase
def getBase(): TBase
}
trait InventoryBridge {
// Whoever is looking at this abstract interface, only knows that
// this is *some* class implementing `ItemBridge`.
// (hence the name "existential types")
type TItemBridge <: ItemBridge
def addItem(item: TItemBridge)
}
// Concrete implementations
class SpongeItemBridge extends ItemBridge {
type TBase = SpongeItem
...
}
class SpongeInventoryBridge extends InventoryBridge {
// ...but whenever referred to via this *concrete* class,
// `TItemBridge` is known to be exactly `SpongeItemBridge`.
// (and by extension, that `TItemBridge.TBase` is `SpongeItem`)
type TItemBridge = SpongeItemBridge
val baseInventory: List[SpongeItem] = ... // This is the "base" inventory, however it's actually represented.
// NOTE: The compiler knows `item.getBase()` returns a `SpongeItem` at this point.
def addItem(item: SpongeItemBridge) = baseInventory.add(item.getBase())
}
(The interfaces have been renamed to have a Bridge suffix to make it a bit clearer)

Better way/design than using large number of getters

Say I have a class which stores a weapon Arsenal
public class Arsenal{
List<RocketLauncher> rocketLaunchers;
List<HandGrenade> handGrenades;
List<LandMine> landMines;
//Followed by a few more weapons
}
The weapons are part of an enum, Weapon
Now, I am trying to display a summary screen or report elsewhere and I am preparing a map. See the snippet below. I have shown two approaches
public Map<Weapon,Integer> generateReport(Arsenal arsenal){
Map<Weapon,Integer> weaponCountMap = //suitable map impl
//Technique 1
//Create and use a larger num of getters from the Arsenal Class
weaponCountMap.put(Weapon.HAND_GRENADE, arsenal.getHandGrenades);
//.. and so on
//Technique 2
//Create a single method in Arsenal which returns a Map
weaponCountMap = arsenal.getSummary();
return weaponCountMap;
}
Question : Is it just me or does everyone feel 'not right' to use a large number of getters. Suppose Arsenal stores around 50 weapons, it's like 50 methods in the class. Double with setters.
Also. I feel less flexible using the 2nd method, with no accessor methods.
Can you guys please critically evaluate both approaches and possibly suggest new ones?
How about not hard-coding types of weapon inside of your Arsenal? The following is simple implementation of heterogeneous container for your specific case. However, as I don't quite familiar with Generics in enum, this implementation is when you have Weapon and their subclasses, e.g. HardGrenade extends Weapon, etc.
public class Arsenal{
private Map<Class<?>, Collection<?>> weaponArsenal;
public <T extends Weapon> Collection<T> get(Class<T> weaponClass) {
if (weaponArsenal.containsKey(weaponClass) {
return (Collection<T>) weaponArsenal.get(weaponClass);
}
return new ArrayList<T>(); // to avoid checking null everytime in client code
}
public <T extends Weapon> void put(T weapon) {
if (!weaponArsenal.containsKey(weapon.class)) {
Collection<T> weaponList = // initialize correct collection here
weaponArsenal.put(weapon.class, weaponList);
}
weaponArsenal.get(weapon.class).add(weapon);
}
}
and in the client code
Arsenal arsenal = new Arsenal();
arsenal.put(new HandGrenade());
arsenal.put(new RocketLauncher());
Collection<HandGrenade> handGrenades = arsenal.get(HandGrenade.class);
Collection<RocketLauncher> rocketLaunchers = arsenal.get(RocketLauncher.class);
In the arsenal you can duplicate the map instead of using lists. Then in the generateReport method you can iterate over the enum and use the enum value to get the suitable list from the map.
Something like
Arsenal:
Map<Weapon,List<Weapon>> weaponsMap;
arsenalMap.put(Weapon.HAND_GRENADE,handGrenades);
generate report:
for (Weapon weapon: Weapon.values()) {
weaponCountMap.put(Weapon.HAND_GRENADE, arsenal.weaponsMap.get(weapon));
}
Might not be the best solution but you will remove some of the getters.
If you make Arsenal immutable and construct it using a builder (to avoid having a bunch of constructors), you can make the instance variables public.
This approach allows you to use technique 1 from your question but without getters, and still keep state management of the object internal to the object.
public class Arsenal {
public final List<RocketLauncher> rocketLaunchers;
public final List<HandGrenade> handGrenades;
public final List<LandMine> landMines;
//Followed by a few more weapons
private Arsenal(final Arsenal.Builder builder) {
this.rocketLaunchers = Collections.unmodifiableList(builder.rocketLaunchers);
this.handGrenades = Collections.unmodifiableList(builder.handGrenades );
this.landMines= Collections.unmodifiableList(builder.landMines);
// and so on
}
public static class Builder {
private final List<RocketLauncher> rocketLaunchers = new ArrayList<>();
private final List<HandGrenade> handGrenades = new ArrayList<>();
private final List<LandMine> landMines = new ArrayList<>();
public Builder rocketLaunchers(List<RocketLauncher> rocketLaunchers) {
this.rocketLaunchers.addAll(rocketLaunchers);
return this;
}
public Builder handGrenades(List<HandGrenade> handGrenades) {
this.handGrenades.addAll(handGrenades);
return this;
}
public Builder landMines (List<LandMines> landMines ) {
this.landMines .addAll(landMines );
return this;
}
public Arsenal build() {
return new Arsenal(this);
}
}
}
You can now use this in the following way.
List<RocketLauncher> rocketLaunchers = //whatever
Arsenal arsenal = new Arsenal.Builder().rocketLaunchers(rocketLaunchers).build();
....
weaponCountMap.put(Weapon.HAND_GRENADE, arsenal.handGrenades);
//.. and so on
All fields of the arsenal are non-null, and can't be modified. If you define the builder in an external class (i.e. not a static class within Arsenal) your Arsenal class will be very small - just fields and the constructor, plus logic methods.
Please have a look at other posts like this one...Java Conventions: use getters/setters WITHIN the class? to obtain an idea on when you could use getters instead of direct access.
Its kind of a design question depending upon what you would like to encapsulate within your arsenal class and what you would like to expose to the outside world for viewing your arsenal.
Its like the UN trying to inspect your arsenal and you tell them hey I wont tell you what weapons I am dealing with in my arsenal but I can give you a report and that is the report you externalize to the outside world. Now it depends on you what report you want to give out and which weapons will land in that map of yours.
Now looking at your second technique, are you planning to shift the map creation logic into your Arsenal class.
Another design question to answer .... is this logic just to obtain reports then my suggestion is to keep it out of the arsenal class and keep it light.
Otherwise you might end up putting in all kind of report logics into the arsenal class and it will get heavier and might explode.
See https://projectlombok.org/ or https://github.com/google/auto/tree/master/value.
Add separate field for each weapon, Lombok or AutoValue will create getters/setters/hashcode/equals/toString methods for you.

Generic or abstract class?

I have in my application three classes User, Group, Company which do not belong to the same inheritance tree, as their names reveal. Each class has a constructor which receives a number of (different) parameters i.e: User(String name, String password, int type), Group(String name, String name), Company(String name, int employees, boolean isValid). The number of the paraameters that each constructors requires is not the same for all the classes. I have created a class ReadDataFromFile to read some data from txt files and to create new Objects passing the data as paaraameters to the above constructors. The code of this class is apparently the same for every type, except for one method which creates the objects. Consequently it is not appropriate to create three distinct classes, but I had better to aim at a better design approach.
My question is whether the opportune design on this occasion is a Generic class, or an abstract class and implementing in its subclass the one method which differs createObject(), assuming that the necessary data coming from the txt file are put into a String array with differnt length for each type. I would like to follow the approach of Generic class: class ReadDataFromFile<T>{} , but I cannot find how I should handle the different types, since each one requires a call of a different constructor. Should I check for the type with instanceof? Should I pass to the method the class of each object? Or is there a better way?
Do not understand why you have posed the question as "abstract or generic" it looks like the common solution would be both.
public abstract class ReadFromFile<T> {
public T readFile(File file) {
String[] rawInput = doSomeStuffCommonToAll();
return constructObject(rawInput);
}
abstract T constructObject(String[] rawInput);
}
public class UserFileReader extends ReadFromFile<User> {
#Override
User constructObject(String[] rawInput) {
return new User(rawInput[0], rawInput[1], Integer.parseInt(rawInput[2]);
}
}
Create your objects based on conditions, for example the "instanceof" validation:
if (objectData instanceof User){
User = new User();
user.setName(objectData.getString(1));
} //...
I think I would choose an abstract design and for instance make use of the abstract factory pattern.
The answer in short, is neither :) Yes you do need abstraction, but it does not have to be of the subclassing form you seem to be leaning towards. Prefer composition over inheritance?
Long answer :) I do not know your domain exactly, but from what you have written I'm assuming you have three files, users.txt, groups.txt and companies.txt, with a shared format but with different data - something like CSV. So you can achieve abstraction through composition by doing something like this, which should illustrate the point even if my assumptions are wrong.
public class FileReader {
public static void read(File f, RowHandler rowHandler) {
//read each line, convert its contents to a map, and pass it to rowHandler
}
}
where
public interface RowHandler {
void handle(Map<String,String> row);
}
This means you separate the reading and parsing of each line from what do to with each parsed line.
To create User objects you could do:
public class UserConstructor implements RowHandler {
private List<User> users = new ArrayList<User);
public void handle(Map<String,String> row) {
users.add(new User(row.get("name"), row.get("password"), Integer.parseInt(row.get("type)));
}
public List<User> getUsers() {
return users;
}
}
And then you connect it all by doing
UserConstructor uc = new UserConstructor();
FileReader.readFile(new File("users.txt), uc);
List<User> users = uc.users();
You use the class name ReadDataFromFile. This name suggests a single purpose, but your question suggests you're mixing another concern into it - so it reads files and creates objects. ReadDataFromFile should just read data from file, and pass the data to another class to implement a strategy to do something with it.
Thats what the above design attempts to do - keep concerns separate.

Generic class method returns its own type as a template parameter

I'm designing a set of generic classes that hold Document objects within Folder objects:
// Folder, which holds zero or more documents
public interface Folder<DocType extends Document>
{
// Locate matching documents within the folder
public ArrayList<DocType> findDocuments(...);
...
}
// Document, contained within a folder
public interface Document
{
// Retrieve the parent folder
public Folder getFolder(); // Not correct
...
}
These classes are then extended for the actual implementation of the folder and document types. The trouble is that the Document.getFolder() method needs to return an object of type Folder<DocType>, where DocType is the actual implementation type of Document. Which means that the method needs to know what its own concrete class type is.
So my question is, should the Document class be declared instead like this:
// Document, contained within a Folder
public interface Document<DocType extends Document>
{
// Retrieve the parent folder
public Folder<DocType> getFolder();
...
}
Or is there a simpler way to do this? The code above requires concrete implementations to look like this:
public class MyFolder
implements Folder<MyDocument>
{ ... }
public class MyDocument
implements Document<MyDocument>
{ ... }
It's the Document<MyDocument> part that seems a bit strange to me; is it really necessary?
(Apologies if this is a duplicate; I couldn't find the exact answer I was looking for in the archives.)
ADDENDUM
The original code above used ArrayList<DocType>, but like several posters have pointed out, I'd be better off returning a List, e.g.:
public List<DocType> findDocuments(...);
(That method was not crucial to my problem, and my actual API returns an Iterator, so I just used the first thing that came to mind in order to simplify the question.)
The way you have it seems to be Ok for me, with the exception of a missing type parameters in the Document and Folder interfaces and the use of ArrayList (an implementation) instead of List (an interface).
interface Folder<T extends Document<T>>
{
public List<T> findDocuments();
}
interface Document<T extends Document<T>>
{
public Folder<T> getFolder();
}
Using the API is the best way to know, let's say we have an implementation of Document called SpreadSheet:
class SpreadSheet implements Document<SpreadSheet> {
#Override
public Folder<SpreadSheet> getFolder() {
return new SpreadSheetFolder();
}
}
And then you have a Folder implementation called SpreadSheetFolder:
class SpreadSheetFolder implements Folder<SpreadSheet>{
#Override
public List<SpreadSheet> findDocuments() {
return asList(new SpreadSheet(), new SpreadSheet());
}
}
Then when you use your API, you would do:
Document<SpreadSheet> d = new SpreadSheet();
Folder<SpreadSheet> folder = d.getFolder();
It works just fine.
That seems an aedequate way to adress your requirements, and no, there is no simpler way to express the same (in particular, Java has no syntax to constrain a type parameter to the type of this).
However, since you extend both Document and Folder, perhaps your actually need a mutually recursive type bound. By which I mean that in your solution, the expression
new MyFolder().findDocuments().get(0).getFolder()
is of type Folder<MyDocument>, not MyFolder. If it needs to be MyFolder, the generics get ugly:
//Folder, which holds zero or more documents
interface Folder<D extends Document<D, F>, F extends Folder<D, F>> {
ArrayList<D> findDocuments();
}
// Document, contained within a folder
interface Document<D extends Document<D, F>, F extends Folder<D, F>> {
F getFolder();
}
You can then implement:
class MyFolder implements Folder<MyDocument, MyFolder> {
#Override
public ArrayList<MyDocument> findDocuments() {
return new ArrayList<>(Collections.singletonList(new MyDocument()));
}
}
class MyDocument implements Document<MyDocument, MyFolder> {
#Override
public MyFolder getFolder() {
return new MyFolder();
}
}
and now,
MyFolder folder = new MyFolder().findDocuments().get(0).getFolder();
compiles, too.
BTW, using ArrayList in an interface is quite restrictive, as the kludge when I wanted to use Collections.singletonList illustrates. You also (inadvertently?) deny yourself the services of Collections.unmodifiableList and friends. Usually, one therefore leaves the List implementation to the discretion of the implementor by declaring
List<D> findDocuments();
instead.

Categories