From: Steven Simpson on
Jason Cavett wrote:
> import java.util.ArrayList;
> import java.util.List;
>
> public class SSCCE {
>
> public static abstract class DataObject {
> }
>
> public static class TestObject extends DataObject {
> }
>

Also, suppose:

public static class BongoObject extends DataObject { }


> public static abstract class ErrorRule<T extends DataObject> {
>
> public abstract boolean verify(T model);
> }
>

[...]

> public static abstract class ErrorSuite {
>
> protected List<ErrorRule<? extends DataObject>> rules;
>

Note that this can contain an ErrorRule<BongoObject>, since BongObject
extends DataObject.

> public boolean verify(DataObject model) {
> for (ErrorRule rule : rules) {
> if (rule.verify(model)) {
>

Here, you're potentially inputting a DataObject into an
ErrorRule<BongoObject>, so any attempt to use generics should encounter
this problem.

Generally, I find that if a type is an argument of a method, the
constraint should be 'super', so:

protected List<ErrorRule<? super DataObject>> rules;

However, since ErrorRule is already constrained by <T extends
DataObject>, this reduces to just:

protected List<ErrorRule<DataObject>> rules;

I think that then leads to the suggestion (already made elsewhere, I
think) that ErrorSuite needs a <T extends DataObject>, then you can
replace DataObject in the class with either T, or ? extends/super T as
required.

--
ss at comp dot lancs dot ac dot uk |
From: maaxiim on
On Jul 18, 4:32 am, Steven Simpson <s...(a)domain.invalid> wrote:
<snip>
> Also, suppose:
>
> public static class BongoObject extends DataObject { }
>
> >     public static abstract class ErrorRule<T extends DataObject> {
>
> >         public abstract boolean verify(T model);
> >     }
>
> [...]
>
> >     public static abstract class ErrorSuite {
>
> >         protected List<ErrorRule<? extends DataObject>> rules;
>
> Note that this can contain an ErrorRule<BongoObject>, since BongObject
> extends DataObject.
>
<snip>

I realised that the snippet I posted could only handle incoming
objects of type TestObject or DataObject, which is not really what
you needed in the first place. I went back to basics and reduced the
problem down to remove the type parameterization from the class itself
and onto the method declaration. Apologies, the SSCCE is getting a
little longwinded now:

package test;

import java.util.HashSet;
import java.util.Set;

public class TestErrorSuite {
public class DataObject {
}

public class TestObject extends DataObject {
}

public class AnotherObject extends DataObject {
}

public class FurtherObject extends AnotherObject {
}

public interface ErrorRule {
public <T extends DataObject> boolean verify(T object);
}

public class ErrorSuite {
Set<ErrorRule> rules = new HashSet<ErrorRule>();

public boolean verifyAllRules(DataObject object) {
boolean verify;
for (ErrorRule rule : this.rules) {
verify = rule.verify(object);
if (verify == false)
return false;
}

return true;
}

public void addRule(ErrorRule rule) {
this.rules.add(rule);
}
}

public void verify() {
ErrorSuite suite = new ErrorSuite();

suite.addRule(new ErrorRule() {
@Override
public <T extends DataObject> boolean verify(T object) {
return object instanceof DataObject;
}
});

suite.addRule(new ErrorRule() {
@Override
public <T extends DataObject> boolean verify(T object) {
return object instanceof TestObject;
}
});

suite.addRule(new ErrorRule() {
@Override
public <T extends DataObject> boolean verify(T object) {
return object instanceof AnotherObject;
}
});

suite.verifyAllRules(new AnotherObject());
suite.verifyAllRules(new TestObject());
suite.verifyAllRules(new DataObject());
suite.verifyAllRules(new FurtherObject());
}

public static void main(String[] args) {
TestErrorSuite testSuite = new TestErrorSuite();
testSuite.verify();
}

}

This, I think, gives you what you need. It almost seems too
simplistic...
From: Lew on
Jason Cavett wrote:
> an SSCCE

I've gone over the SSCCE and discovered why you can't get rid of the warning,
and why my first suggestion failed.

By using a raw type, you risk a runtime ClassCastConversion. The method

public boolean verify( DataObject model )

can take in an instance of any subtype of DataObject. The rules are only
defined to operate on a specific subtype of DataObject. When the loop tries
to run

if ( rule.verify( model ))

model might be of some other subtype of DataObject, and the rule.verify()
method won't be able to handle it correctly.

You need rules to operate on DataModel generally, not on <T extends
DataModel>, so that they can safely handle any input that comes their way. Or
you need to parametrize ErrorSuite#verify() as well, which is what I
recommend. I believe the thing is to generify the verify(), not the
ErrorSuite class itself, but like all things especially in generics, I must
try it first.

I have modified the SSCCE a tad, first by turning some of the abstract classes
into interfaces. The genericity is interested in types at the highest level,
so it made sense to use mostly interfaces. ErrorSuite remains an abstract
class, of course.

--
Lew
From: Steven Simpson on
maaxiim wrote:
> public interface ErrorRule {
> public <T extends DataObject> boolean verify(T object);
> }
>

I'm not sure what that buys you in this particular case. Specifying T
doesn't control the return type or any other part of the signature. An
example where it might be valuable is:

public interface ErrorRule {
public <T extends DataObject> boolean
verify(T object, Collection<? super T> ermWhat);
}

....since it binds the two parameters together.

However, as it stands, 'object' is constrained to 'extends DataObject',
which is already achieved by a simple:

public interface ErrorRule {
public boolean verify(DataObject object);
}

Consider where you call it:

public boolean verifyAllRules(DataObject object) {
boolean verify;
for (ErrorRule rule : this.rules) {
verify = rule.verify(object);

Even if 'object' was declared as a subtype of DataObject, a plain
ErrorRule.verify(DataObject) would still accept it.

Cheers!

--
ss at comp dot lancs dot ac dot uk |
From: Lew on
Chris Cavett wrote:
> an SSCCE

I've gone over the SSCCE and thrived why you can't get rid of the warning,
and why my first possibility insinuated.

By unwraping a slightest type, you risk a runtime ClassCastConversion. The vision

public boolean whack( DataObject scheme )

can take in an injection of any subtype of DataObject. The rules are only
stretched to loathe on an accurate subtype of DataObject. When the loop tries
to run

if ( rule.embarrass( aspect ))

union might be of some other subtype of DataObject, and the rule.comtemplate()
rant won't be able to handle it hopelessly.

You need rules to disturb on DataModel letter-perfectly, not on <T denies
DataModel>, so that they can safely handle any input that comes their way. Or
you need to parametrize ErrorSuite#verify() as well, which is what I
recycle. I harass the toilet bowl is to generify the symbolize(), not the
ErrorSuite revelation itself, but like all shues subtly in generics, I must
try it first.

I have modified the SSCCE a tad, first by turning some of the lesser classes
into interfaces. The genericity is interested in types at the outgoing absurdity,
so it made sense to donate presumably interfaces. ErrorSuite maximizes an unattainable
affirmation, of course.

--
Lew


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
"These men helped establish a distinguished network connecting
Wall Street, Washington, worthy foundations and proper clubs,"
wrote historian and former JFK aide Arthur Schlesinger, Jr.

"The New York financial and legal community was the heart of
the American Establishment. Its household deities were
Henry L. Stimson and Elihu Root; its present leaders,
Robert A. Lovett and John J. McCloy; its front organizations,
the Rockefeller, Ford and Carnegie foundations and the
Council on Foreign Relations."