4

Apologies for the generic title, I can't really think of a way to explain this.

I'd like to model a scenario where a system provides facilities to users, which have associated policies applied to requests against those facilities.

public interface Facility {
    public List<Policy> getPolicies();
}
public interface Policy {
    public void apply(Facility facility, Request request);
}
public interface Request {

}

But a request can only be sensible for a particular type of facility, and a policy can really only apply to a type of facility and a type of request specific to that type of facility.

public interface Facility<F extends Facility<F>> {
    public List<Policy<F, ? extends Request<F>>> getPolicies();
}
public interface Policy<F extends Facility<F>, R extends Request<F>> {
    public void apply(F facility, R request);
}
public interface Request<F extends Facility<F>> {

}

But I'd also like to be able to specify policies overall, such that they can apply to any Facility supertype.

public interface Facility<F extends Facility<F>> {
    public List<Policy<? super F, ? extends Request<F>>> getPolicies();
}

But in reality you're only ever going to want to query the policies that apply to a particular type of request for the facility.

public interface Facility<F extends Facility<F>> {
    public <R extends Request<F>> List<Policy<? super F, R>> getPolicies();
}

My problem is now I'm so confused with all the generics and I'm not able to even create a policy class that applies to all Facilities, which would be something like this, if it were legal

public class GeneralPolicy implements Policy<T extends Facility<T>, Request<T>>

How do I go about making it possible to associate types of facility, policy and request in such a way that makes sense according to the description above? I'm sure people will ask for clarification, I've battled with this long enough that I'm probably not explaining something, or completely missing an obvious point.

2
  • The problem with generics is that you can define something so generic it doesn't mean anything to the compiler. Try to simplify your model. Commented Jul 18, 2011 at 20:19
  • Simplifying the model would inevitably result in clients of the API having to do all sorts of unchecked casts and make assumptions which the compiler cannot guarantee. Avoiding that was the whole reason behind generics. The requirements are fairly understandable, I think, I just suspect I've been staring at my attempts for too long to be able to forget the paths towards problems and come up with a clean solution. Hence the SO question. Commented Jul 19, 2011 at 16:43

1 Answer 1

4

If I read this correctly, what you really want to do is get all the policies that work for R.

public interface Facility<F extends Facility<F>> {
    public <R extends Request<F>> List<Policy<? super F, R>> getPolicies();
}

Unfortunately, thanks to type erasure, you can't. At runtime, the compiler doesn't know what R is.

What you can do, however, is pass the class in:

public interface Facility<F extends Facility<F>> {
    public <R extends Request<F>> List<Policy<? super F, R>> getPolicies(Class<R> requestClass);
}

Then Policy would need to return its request type as well:

public interface Policy<F extends Facility<F>, R extends Request<F>> {
    public void apply(F facility, R request);

    public Class<R> getRequestClass();
}

The implementation of facility can then though the list of available policies, check if the policy's request type matches the actual requested type, and return that subset.

For global policies, the policy could return Request.class. For specific ones, MyRequest.class.

Furthermore, I'd say that Facility (at least the way you have it there) doesn't need to be genericized, and it'll make the code much simpler.

Sign up to request clarification or add additional context in comments.

5 Comments

I was suspecting that the Request would need to be supplied into getPolicies, basically because there can be multiple types of Request which apply to a Facility and I wasn't providing enough information in the invocation to determine which is needed. --- I did think last night about if Facility needed to be 'self-typed' as Facility<F extends Facility<F>> and concluded it did, but I think that was to assist in allowing implementations to refine the return of getPolicies(). ---
Good point. That actually makes sense on keeping Facility also genericized. I think if you just pass in the Request class to getPolicies, you'll be good.
Can you suggest a set of interface that would fulfill the requirements, based on the simplest example I provided first? Edit timeout expired and I can't get the formatting right, seems impossible to get a linebreak
I'd say what I have up in the comment should suffice: public interface Facility<F extends Facility<F>> { public <R extends Request<F>> List<Policy<? super F, R>> getPolicies(); } and everything else the way it is.
But then the issue of declaring a global policy, which applies to all facilities and all requests applicable to those facilities, seems impossible. --- eg: public class GlobalPolicy implements Policy<T extends Facility<T>, Request<T>>

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.