3

I asked a similar question this morning, thought I had it answered, actually implemented the proposed solution, and it failed to do what I need. So here's my full problem:

I have the following classes:

// Objects to process.
public class Apple {
    private Color color;
    private int numberOfSeeds;
    // ...
}

public class Chair {
    private Material madeOutOfMaterial;
    private double price;
    // ...
}

public class CellPhone {
    private Manufacturer make;
    private String model;
    private boolean isSmartPhone;
    // ...
}

// Contains the object that will be processed (an Apple, Chair, CellPhone instance, etc.)
// as well as metadata info about the processing itself (timestamp, a UUID for tracking
// purposes, etc.).
public class ProcessingMetadata<PROCESSABLE_OBJECT> {
    private PROCESSABLE_OBJECT result;
    private Date processedOnDate;
    private String uuid;
    // ...
}

// Abstract base class for processing PROCESSABLE_OBJECTs.
public abstract class ObjectProcessor<ProcessingMetadata<PROCESSABLE_OBJECT>> {
    private String name;

    public abstract ProcessingMetadata<PROCESSABLE_OBJECT> process(Data data);
}

// One concrete processor.
public class SimpleObjectProcessor extends ObjectProcessor<ProcessingMetadata<PROCESSABLE_OBJECT>> {
    private Fizz fizz;

    @Override
    public ProcessingMetadata<PROCESSABLE_OBJECT> process(Data data) {
        // Processes data one way, and returns a PROCESSABLE_OBJECT.
    }
}

// Another concrete processor.
public class ComplexObjectProcessor extends ObjectProcessor<ProcessingMetadata<PROCESSABLE_OBJECT>> {
    private Buzz buzz;

    @Override
    public ProcessingMetadata<PROCESSABLE_OBJECT> process(Data data) {
        // Processes data differently, and returns a PROCESSABLE_OBJECT.
    }
}

So that the final code, using all of these classes looks like this:

ObjectProcessor<ProcessingMetadata<Apple>> appleProcessor =
        new ComplexObjectProcessor<ProcessingMetadata<Apple>>();
Data data = getData();

ProcessingMetadata<PROCESSABLE_OBJECT> meta = appleProcessor.process(data);

Apple apple = meta.getResult();
Date processedOn = meta.getProcessedOnDate();
String uuid = meta.getUUID();

This is the "API" that I want exposed to the developer. Grab some Data, select a typed processor, process the data, and get all the metadata you need.

The problem is that my ObjectProcessor<ProcessingMetadata<PROCESSABLE_OBJECT>> isn't legal. It gives me the following compiler error on the ProcessingMetadata portion of the class definition:

Syntax error on token(s), misplaced construct(s)

I have played with this class (and its concrete subclasses) all morning, and can't seem to get generics set up correctly to give me the API that I want. I'm open to requiring the PROCESSABLE_OBJECTs to actually being an interface, such as Processable, and having Apple, Chair, etc. implement it. But there's no telling what the client is going to want to process, and so I'd prefer not to force them to make their POJOs implement a Processabl interface, if at all possible.

So, is my desired API possible? If so, how? If not, then why, and what is the closest I can get to it? Thanks in advance!

1
  • Try adding a space to the ending >>: > >. Commented Jun 27, 2013 at 16:30

3 Answers 3

3

Each of the items in the type parameter list needs to be a type parameter. In the class declaration of ObjectProcessor, ProcessingMetadata<PROCESSABLE_OBJECT> is not a generic type parameter.

You could specify PROCESSABLE_OBJECT as a parameterized type, and then specify a type extending ProcessingMetaData as another parameterized type.

public abstract class ObjectProcessor< 
   PROCESSING_METADATA extends ProcessingMetadata<PROCESSABLE_OBJECT>, 
   PROCESSABLE_OBJECT > 
{ ... }

EDIT:

Your subclasses are also parameterized types. You need to declare those type parameters on the class itself. Then you can use them to parameterize the superclass.

public class SimpleObjectProcessor<
   PROCESSING_METADATA extends ProcessingMetadata<PROCESSABLE_OBJECT>, 
   PROCESSABLE_OBJECT > 
extends ObjectProcessor< PROCESSING_METADATA,PROCESSABLE_OBJECT > 
{ ... }
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks @Andy Thomas (+1) - can you show me what one of the concrete processors' definition might look like (SimpleObjectProcessor or ComplexObjectProcessor, etc.)?
1

I think in your api, the developer would use this line

ProcessingMetadata<PROCESSABLE_OBJECT> meta = appleProcessor.process(data);

as this

ProcessingMetadata<Apple> meta = appleProcessor.process(data);

Comments

0

The class declaration itself only takes a type parameter declaration, but you try to put ProcessingMetadata there.

public abstract class ObjectProcessor<PROCESSABLE_OBJECT> {
    private String name;

    public abstract ProcessingMetadata<PROCESSABLE_OBJECT> process(Data data);
}

public class SimpleObjectProcessor<PROCESSABLE_OBJECT>
        extends ObjectProcessor<PROCESSABLE_OBJECT> {
    private Fizz fizz;

    @Override
    public ProcessingMetadata<PROCESSABLE_OBJECT> process(Data data) {
        // Processes data one way, and returns a PROCESSABLE_OBJECT.
    }
}

ObjectProcessor<Apple> appleProcessor = new ComplexObjectProcessor<Apple>();
// Note: there is no PROCESSABLE_OBJECT here. Use the concrete type:
ProcessingMetadata<Apple> meta = appleProcessor.process(data);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.