JOOQ choose field Converter by another field - java

I want to convert between Set of Enum POJO and String[] Database(postgres) column.
and the enum class would be changed by another field type.
So I can say Enum class which's using in fooSet is changable and it's up to field type.
I know it's a messy. but I need a help.
Below are models
public interface A {
enum B implements A {
step1,
step2,
step3
}
enum C implements A {
step4,
step5,
step6
}
}
public abstract class Foo {
private String type;
}
public abstract class FooA {
private Set<B> fooSet;
}
public abstract class FooB {
private Set<C> fooSet;
}
I want to make a Converter like below.
SetOfEnumConverter<U extends Enum<U> & A> implements Converter<String[], Set<U>> {
#Override
public Set<U> from(String[] databaseObject) {
if (databaseObject == null) {
return null;
}
return Arrays.stream(databaseObject)
.map(x -> U.valueOf(U.class, x)). // here's the problem point
.collect(Collectors.toSet());
}
#Override
public String[] to(Set<U> userObject) {
if (userObject == null || userObject.isEmpty()) {
return null;
}
String[] strings = userObject.stream()
.map(Enum::name)
.toArray(String[]::new);
return ArrayUtils.isEmpty(strings) ? new String[0]: strings;
}
#Override
public Class<String[]> fromType() {
return String[].class;
}
#Override
public Class<Set<U>> toType() {
return (Class) TreeSet.class;
}
}
But the problem is I can't point .class attribute from a generic type maybe because of Generic Type erasure.
So, What I want to do is mapping the setEnum class to be used in the field fooSet according to the field type.
Because I have to make a single table for Foo and map from FooA, FooB and FooZ.

You can't do this without passing an actual Class<U> reference to your converter, e.g. like this:
SetOfEnumConverter<U extends Enum<U> & A> implements Converter<String[], Set<U>> {
final Class<U> u;
SetOfEnumConverter(Class<U> u) {
this.u = u;
}
// ...
}
And inside of the converter, you can use:
Enum.valueOf(u, x)
To look up arbitrary enum values by their names. Then, instantiate it with e.g.
new SetOfEnumConverter<>(MyEnum.class);

Related

How to get element from a list of interface implementations by implementation name

I have a list of implementations to SomeInterface
List<SomeInterface> listOfThingsThatImplementsSomeInterface
I want to extract a specific implementation from the list according to its class name
private SomeInterface getThisType(SomeInterfaceImpl myType) {
SomeInterfaceImpl impl = null
for (SomeInterface current: listOfThingsThatImplementsSomeInterface) {
if (current instanceof myType) {
impl = current
break;
}
}
return impl;
}
Is that possible in Java? should I be using generics?
First you need the Class instance of the desired class (which you have, you mention "according to its class name"). You can get a Class instance from the class name using
Class<?> cls = SomeInterfaceImpl.class;
or if you have the class name as a String:
Class<?> cls = Class.forName("package.ClassName")
or from an instance using
SomeInterfaceImpl myType = ...;
Class<?> cls = myType.getClass()
Then you can call this method, assuming your have a List<SomeInterface> listOfThingsThatImplementsSomeInterface somewhere:
private SomeInterface getThisType(Class<?> myType) {
for (SomeInterface current: listOfThingsThatImplementsSomeInterface) {
if (myType.isInstance(current)) {
return current;
}
}
return null; //nothing found
}
Suppose we have the desired implementation Class instance, (refer to #f1sh answer if the class is Class<?>), it can be done using Stream,
private <T extends SomeInterface> Optional<T> getThisType(Class<T> type) {
return this.someInterfaceList.stream().filter(type::isInstance)
.map(type::cast).findFirst();
}
The key to match the type is using Class#isInstance.
Some points to note:
Make method return type generic so no cast is needed.
Class#cast can be used to convert the return type of the Stream.
Use Optional to handle case when no element matched.
Full example
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class FilterByClass {
List<SomeInterface> someInterfaceList = new ArrayList<>();
public static void main(String[] args) {
FilterByClass filterByClass = new FilterByClass();
filterByClass.someInterfaceList = List.of(new SomeInterfaceImplA(), new SomeInterfaceImplB(), new SomeInterfaceImplC());
System.out.println(filterByClass.getThisType(SomeInterfaceImplA.class).get().name());
System.out.println(filterByClass.getThisType(SomeInterfaceImplB.class).get().name());
System.out.println(filterByClass.getThisType(SomeInterfaceImplC.class).get().name());
}
private <T extends SomeInterface> Optional<T> getThisType(Class<T> type) {
return this.someInterfaceList.stream().filter(type::isInstance)
.map(type::cast).findFirst();
}
public interface SomeInterface {
default String name() {
return this.getClass().getSimpleName();
}
}
public static class SomeInterfaceImplA implements SomeInterface { }
public static class SomeInterfaceImplB implements SomeInterface { }
public static class SomeInterfaceImplC implements SomeInterface { }
}
The method should take the class as parameter. Let's say your interface is T, you can receive a parameter of type Class<? extends T>
Then go through the list and check for an element with the same class
Here is an example that should work:
private static <T> Optional<T> getThisType(
List<T> listOfThingsThatImplementsInterfaceT,
Class<? extends T> klass) {
return listOfThingsThatImplementsInterfaceT.stream()
.filter(klass::isInstance)
.findFirst();
}
Test with a list of Serializable
List<Serializable> listOfThingsThatImplementsSerializable = Arrays.asList(
new Integer(1), new Float(2), new Double(3)
);
System.out.println(
getThisType(listOfThingsThatImplementsSerializable, Float.class)
);
Looking for the Float returns Optional[2.0]

Step builder pattern using delegation and enums?

I have this project I'm working on and basically this is what I would like to achieve.
This is what I have:
MyObject obj = MyObject.builder()
.withValue("string")
.withAnotherValue("string")
.build();
MyObject obj = MyObject.builder()
.withValue("string")
.withAnotherValue("string")
.withField("key", "value")
.build();
So the step builder pattern forces the user to use the withValue() method and the withAnotherValue() method in that order. The method field() is optional and can be used as many times as you want.I followed this website for example http://www.svlada.com/step-builder-pattern/
So what I would like to achieve is this:
MyObject obj = MyObject.builder(Type.ROCK)
.withColour("blue")
.withValue("string")
.withAnotherValue("string")
.build();
MyObject obj = MyObject.builder(Type.STONE)
.withWeight("heavy")
.withValue("string")
.withAnotherValue("string")
.withField("key", "value")
.build();
So in the builder() method you'd put an enum type and based on the enum you'd have a different set of methods appear. So for ROCK the withValue(),withAnotherValue() and withColour() are now mandatory. But for STONE withWeight(), withAnotherValue() and withColour() are mandatory.
I something like this possible? I have been trying for the past two days to figure this out but I just can't seem to get it to give specific methods for each type. It just shows all the methods in the Builder.
Any thoughts and help is much appreciated.
Code:
Enum
public enum Type implements ParameterType<Type> {
ROCK, STONE
}
ParameterType
interface ParameterType<T> {}
MyObject
public class MyObject implements Serializable {
private static final long serialVersionUID = -4970453769180420689L;
private List<Field> fields = new ArrayList<>();
private MyObject() {
}
public interface Type {
Value withValue(String value);
}
public interface Value {
Build withAnotherValue(String anotherValue);
}
public interface Build {
MyObject build();
}
public Type builder(Parameter type) {
return new Builder();
}
public static class Builder implements Build, Type, Value {
private final List<Field> fields = new ArrayList<>();
#Override
public Build withAnotherValue(String anotherValue) {
fields.add(new Field("AnotherValue", anotherValue));
return this;
}
#Override
public Value withValue(String value) {
fields.add(new Field("Value", value));
return this;
}
#Override
public MyObject build() {
MyObject myObject = new MyObject();
myObject.fields.addAll(this.fields);
return myObject;
}
}
}
This isn't possible using enum, but you could do this with a custom enum-like class:
public final class Type<B extends MyObject.Builder> {
private final Supplier<? extends B> supplier;
private Type(Supplier<? extends B> supplier) {
this.supplier = Objects.requireNonNull(supplier);
}
public B builder() {
return supplier.get();
}
public static final Type<MyObject.RockBuilder> ROCK =
new Type<>(MyObject.RockBuilder::new);
public static final Type<MyObject.StoneBuilder> STONE =
new Type<>(MyObject.StoneBuilder::new);
}
public class MyObject {
// ...
// And this method is probably superfluous at this point.
public static <B extends MyObject.Builder> builder(Type<? extends B> type) {
return type.builder();
}
}
You could adapt that approach to a step builder easily, but there's a separate issue here. Since each step in a step builder specifies the next step in the return type, you can't re-use step interfaces very easily. You would need to declare, for example, separate interfaces RockValueStep, StoneValueStep, etc. because the interfaces themselves specify the step order.
The only simple way around that would be if the separate types (rock, stone, etc.) only strictly added steps such that e.g. Type.ROCK returns a ColourStep and Type.STONE returns a WeightStep, and both ColourStep and WeightStep return ValueStep:
// Rock builder starts here.
interface ColourStep { ValueStep withColour(String c); }
// Stone builder starts here.
interface WeightStep { ValueStep withWeight(String w); }
// Shared.
interface ValueStep { AnotherValueStep withValue(String v); }
And then:
public final class Type<B /* extends ABuilderStepMarker, possibly */> {
// (Constructor and stuff basically same as before.)
public static final Type<MyObject.ColourStep> ROCK =
new Type<>(/* implementation */::new);
public static final Type<MyObject.WeightStep> STONE =
new Type<>(/* implementation */::new);
}
The reasons this kind of thing can't be done using enum are pretty much:
enum can't be generic:
// This is an error.
enum Type<T> {
}
Although you could declare an abstract method on an enum and override it with a covariant return type, the covariant return type is never visible:
// This is valid code, but the actual type of
// Type.ROCK is just Type, so the return type of
// Type.ROCK.builder() is just MyObject.Builder,
// despite the override.
enum Type {
ROCK {
#Override
public MyObject.RockBuilder builder() {
return new MyObject.RockBuilder();
}
};
public abstract MyObject.Builder builder();
}
Considering you are looking for specific methods for a specific type of builder, having multiple builders, one for each type of MyObject that can be built may work best. You can create an interface that defines the builder and then put the common functionality into an abstract class, from which the individual builders extend. For example:
public interface Builder {
public MyObject build();
}
public abstract class AbstractBuilder() {
private final List<Field> fields = new ArrayList<>();
protected void addField(String key, String value) {
fields.add(new Field(key, value));
}
#Override
public MyObject build() {
MyObject myObject = new MyObject();
myObject.fields.addAll(this.fields);
return myObject;
}
}
public class StoneBuilder extends AbstractBuilder {
public StoneBuilder withValue(String value) {
addField("Value", value);
return this;
}
// ...More builder methods...
}
public class RockBuilder extends AbstractBuilder {
public RockBuilder withAnotherValue(String value) {
addField("AnotherValue", value);
return this;
}
// ...More builder methods...
}
This allows you to build MyObject instances in the following manner:
MyObject obj = new RockBuilder()
.withValue("string")
.build();
MyObject obj = new StoneBuilder()
.withAnotherValue("string")
.build();
Your question can be generalised as follows: "How can I write the following method?"
public <T extends AbstractBuilder> T builder(final SomeNonGenericObject object) {
// code goes here
}
And the answer is: "You cannot, because there is no way for the compiler to infer what the type of T is. The only way that this is possible is by somehow passing T as a parameter:
public <T extends AbstractBuilder> T builder(final SomeNonGenericObject object, final Class<T> builderClass) {
// code goes here
}
or
public <T extends AbstractBuilder> T builder(final SomeGenericObject<T> object) {
// code goes here
}
For example:
public <T extends AbstractBuilder> T builder(final Supplier<T> object) {
return supplier.get();
}
final Supplier<AbstractBuilder> rockBuilderSupplier = RockBuilder::new;
builder(rockBuilerSupplier)
.withColour("blue")
// etc
Or simply use Justin Albano's answer, which works just as well.

Java Generics and Enum, loss of template parameters

I have a fairly complicated structure, and it is not working as intended. This is what I did:
public interface ResultServiceHolder {
<M, ID extends Serializable, BO extends BusinessObject<M, ID>> ResultService<M, ID, BO> getService();
}
public enum ResultTypes implements ResultServiceHolder {
RESULT_TYPE_ONE {
#Override
public ResultOneService getService() { //unchecked conversion?
return serviceInitializer.getResultOneService();
}
},
RESULT_TYPE_TWO {
#Override
public ResultTwoService getService() { //unchecked conversion?
return serviceInitializer.getResultTwoService();
}
},
RESULT_TYPE_THREE {
#Override
public ResultThreeService getService() { //unchecked conversion?
return serviceInitializer.getResultThreeService();
}
};
protected ServiceInitializer serviceInitializer;
protected void setServiceInitializer(ServiceInitializer serviceInitializer) {
this.serviceInitializer = serviceInitializer;
}
#Component
public static class ServiceInitializer {
#Autowired
private ResultOneService resultOneService;
#Autowired
private ResultTwoService resultTwoService;
#Autowired
private ResultThreeService resultThreeService;
#PostConstruct
public void init() {
for(ResultTypes resultType : ResultTypes.values()) {
resultType.setServiceInitializer(this);
}
}
//getters
}
}
The purpose was to generalize the call based on enums, and rather, just be able to iterate on the array of enums.
for(ResultServiceHolder resultServiceHolder : ResultTypes.values()) {
if(resultServiceHolder.equals(post.getPostResultTypeCode())) {
return resultServiceHolder.getService().createResultSearchCriteriaResponse(postId);
}
}
And this is working fine and dandy. However, if I'd say
ResultTypes.RESULT_TYPE_ONE.getService().getRepository()
Then it is a BaseRepository<Object, Serializable> rather than a BaseRepository<ResultTypeOne, Long>. The method resultTypeHolder.getService() gives back ResultService<M, ID, BO>, but in the end, it becomes Object andSerializable.
What am I doing wrong? How can I retain the generic parameter types?
I'd like to add that yes, I do realize the problem is somewhere with the unchecked casting. But the services are defined as
public interface ResultTypeOneService
extends ResultService<ResultTypeOne, Long, ResultTypeOneBO> {
}
And I don't know why the types are not inferred.
EDIT: Technically, it works if I explicitly infer them:
ResultTypes.RESULT_TYPE_ONE.<ResultTypeOne, Long, ResultTypeOneBO>getService().getRepository()
But it ought to be automatic, why is it not working automatically? Am I supposed to provide it with some kind of object that contains the type? Why is the return type not enough for that?
EDIT2: The superclass of the ResultTypeOne is
#SuppressWarnings("serial")
#EntityListeners(EntityListener.class)
#MappedSuperclass
public abstract class EntityBase implements Serializable {
But it is not mapped anywhere in the bounds.
EDIT3: A big thank you to #Radiodef! The theoretic solution ended up to be the following, and would work perfectly fine:
public interface ResultServiceHolder<M, ID extends Serializable, BO extends BusinessObject<M, ID>> {
ResultService<M, ID, BO> getService();
}
public abstract class ResultTypes<M, ID extends Serializable, BO extends BusinessObject<M, ID>>
implements ResultServiceHolder<M, ID, BO> {
public static ResultTypes<?, ?, ?>[] values() {
return new ResultTypes<?, ?, ?>[] {RESULT_ONE, RESULT_TWO, RESULT_THREE};
}
public static final ResultTypes<ResultOne, Long, ResultOneBO> RESULT_ONE = new ResultTypes<ResultOne, Long, ResultOneBO>("Result One") {
#Override
public ResultOneService getService() {
return serviceInitializer.resultOneService;
}
};
public static final ResultTypes<ResultTwo, Long, ResultTwoBO> RESULT_TWO = new ResultTypes<ResultTwo, Long, ResultTwoBO>("Result Two") {
#Override
public ResultTwoService getService() {
return serviceInitializer.resultTwoService;
}
};
public static final ResultTypes<ResultThree, Long, ResultThreeBO> RESULT_THREE = new ResultTypes<ResultThree, Long, ResultThreeBO>("Result Three") {
#Override
public ResultThreeService getService() {
return serviceInitializer.resultThreeService;
}
};
protected String name;
protected ServiceInitializer serviceInitializer;
private ResultTypes(String name) {
this.name = name;
}
protected void setServiceInitializer(ServiceInitializer serviceInitializer) {
this.serviceInitializer = serviceInitializer;
}
#Component
static class ServiceInitializer {
#Autowired
private ResultOneService resultOneService;
#Autowired
private ResultTwoService resultTwoService;
#Autowired
private ResultThreeService resultThreeService;
#PostConstruct
public void init() {
for (ResultTypes resultType : ResultTypes.values()) {
resultType.setServiceInitializer(this);
}
}
}
}
I think because of how lengthy the solution becomes, I'll stick with the enum approach, and just accept this loss of bounds. I lose more by having to add my own values() implementation than I gain from enforcing these bounds. However, this is an interesting theoretical exercise, and thank you again for your help.
Okay, first you need to understand why what you're doing is probably not what you think it's doing. Let's look at a simpler example.
interface Face {
<T> List<T> get();
}
What you have there is a generic method, get. A generic method's type parameter depends on what is supplied by the call site. So for example like this:
Face f = ...;
// this call site dictates T to be Number
List<Number> l = f.<Number>get();
When you override it like
class Impl implements Face {
#Override
public List<String> get() { return ...; }
}
This is something you are able to do (only because of erasure) but you probably shouldn't. It's only allowed for backwards compatibility to non-generic code. You should listen to the warning and not do it. Doing it means that for example I can still come along and dictate it to return something else:
Face f = new Impl();
// now I've caused heap pollution because you
// actually returned to me a List<String>
List<Number> l = f.<Number>get();
This is why there is an unchecked conversion.
What you probably meant is to use a generic interface declaration:
interface Face<T> {
List<T> get();
}
Now the argument to T depends on the type of the object reference.
Face<Number> f = ...;
// get must return List<Number>
List<Number> l = f.get();
We can implement it like
class Impl implements Face<String> {
#Override
public List<String> get() { return ...; }
}
Additionally, you cannot access covariant return types on an enum. When you override methods on an enum constant, its class is anonymous. An anonymous class has no name and cannot be referred to. Therefore the programmer cannot know its covariant return type to use it. Furthermore, an enum cannot declare generic type parameters. So what you are wanting to do is simply impossible with enum.
You can use a class with public static final instances to simulate a generic enum:
public abstract class SimEnum<T> implements Face<T> {
public static final SimEnum<Number> A = new SimEnum<Number>() {
#Override
public List<Number> get() { return ...; }
};
public static final SimEnum<String> B = new SimEnum<String>() {
#Override
public List<String> get() { return ...; }
};
private SimEnum() {}
public static SumEnum<?>[] values() {
return new SimEnum<?>[] { A, B };
}
}
Otherwise you need to drastically change your idea.
Maybe use an interface/abstract class instead of an enum?
Enums cannot have type parameters but classes and interfaces can.
For example...
Interfaces
Entity.java
The "thing" interface...
import java.io.Serializable;
public interface Entity<K extends Serializable> {
// TODO: Put entity type things here!
// for example, things like "K getId();"
// You may want an abstract base class for this interface that all Entitys extend
}
Repository.java
Does CRUD stuff with things...
import java.io.Serializable;
public interface Repository<K extends Serializable, V extends Entity<K>> {
V getValue(K key);
// Other CRUD stuff
}
Service.java
A Service is responsible for doing stuff with things...
public interface Service<K, V> {
// Could have an abstract service class that has a repository and implements this for you...
V get(K key);
// Other "generic service" type stuff
}
Solid Classes
Entity1.java
Solid base class with String key...
public class Entity1 implements Entity<String> {
// TODO implement Entity stuff...
}
Entity2.java
Solid base class with Integer key...
public class Entity2 implements Entity<Integer> {
// TODO implement methods...
}
Entity1Service.java
Solid Entity1 Service
public class Entity1Service implements Service<String, Entity1> {
// Would not have to implement this if you extended an abstract base Service class
#Override
public Entity1 get(String key) {
return null;
}
}
Entity2Service.java
Solid Entity2 Service
public class Entity2Service implements Service<Integer, Entity2> {
// Wouldn't need this if you had abstract Service class either...
#Override
public Entity2 get(Integer key) {
return null;
}
}
ServiceHolder.java
Not an enum, but an interface - you could add methods to set the "service" from spring or something here...
import java.io.Serializable;
public abstract class ServiceHolder<K extends Serializable, V, S extends Service<K, V>> {
public static final ServiceHolder<String, Entity1, Entity1Service> ENTITY_1_SERVICE = new ServiceHolder<String, Entity1, Entity1Service>() {};
public static final ServiceHolder<Integer, Entity2, Entity2Service> ENTITY_2_SERVICE = new ServiceHolder<Integer, Entity2, Entity2Service>() {};
private S service;
private ServiceHolder() {
}
public S getService() {
return service;
}
public void setService(S service) {
this.service = service;
}
}
The interesting bit
I think this is the sort of thing you wanted, please let me know if I misunderstood...
public class PleaseCompile {
public static void main(String[] args) {
Entity1 solid1 = ServiceHolder.ENTITY_1_SERVICE.getService().get("[KEY]");
Entity2 solid2 = ServiceHolder.ENTITY_2_SERVICE.getService().get(42);
...
}
}
Hope this helps...
You cannot do what you want to do.
List<String> and List<Integer> face type erasure at runtime.
And so do your enum-mapped getService() functions.
Everything related to types for generics is validated at compile-time.

When should I pass a class as an argument?

I am confused to undrestand when we should pass a class as an argument instead of its instance.
for example:
myMethod(classA.class);
Could you make an example of when and how we should pass a class as an argument?
A classic example is when creating an instance of a class through reflection:
//avoiding exception handling, leave that up to you
static <T> T make(Class<T> clazz) {
return clazz.newInstance();
}
//...
A a = make(A.class);
Also, when you want to make sure at compile time that some references belong to a specific class, as used in Collections#checkedXxx.
For example,If you want to encapsulate many fields' value to an entity such as the Hibernate framework's method "session.get(Class entityClass,String primaryKey)" .You need to define the entityClass so that Hibernate know how to encapsulate the query result into an entity.
A simple example to use Class as a argument:
public T getInstance(Class<T extends Serializable> clazz) throws Exception
{
// the ParameterType "T extend Serializable" means that:
// the argument clazz must be a sub of the Interface Serializable
if(null != clazz)
{
return clazz.newInstacne();
}
return null;
}
Lets consider that we have some Creator
abstract class Creator<T>
{
Creator(Class<T> c)
{
this.c = c;
}
T addMainElement(Object obj)
{
return c.cast(this);
}
private Class<T> c;
}
And some wrapper
class CreatorWrapper extends Creator<CreatorWrapper>
{
CreatorWrapper() {
super(CreatorWrapper.class);
}
CreatorWrapper addMinorElement(Object obj)
{
return this;
}
}
The main advantage of doing this that way is that we can use our creator like that
CreatorWrapper creator = new CreatorWrapper()
.addMainElement(someObj1)
.addMinorElement(someObj2);
We won't be able to do this if base class have no knowledge about child class.
And we won't be disturbed by "Unchecked cast from main.Creator to T" warning as we will be if we cast like that
return (T)this;
See Java Class.cast() vs. cast operator
Silly example:
public class PassClassExample {
public static class ClassValidator {
private Class theClass;
public ClassValidator(Class theClass) {
this.theClass = theClass;
}
public boolean instanceOf(Class someClass) {
return theClass == someClass;
}
}
public static void main (String [] args ) {
ClassValidator personValidator = new ClassValidator(Person.class);
Person you = new Person();
Animal me = new Animal();
System.out.println(personValidator.instanceOf(you.getClass()));
System.out.println(personValidator.instanceOf(me.getClass()));
}
public static class Person {
}
public static class Animal {
}
}
Will print out
true
false
Indicating you are a person and I am an animal :)

Eliminate type parameter of java generics

The code:
interface Property<T>
{
T get();
}
class BoolProperty implements Property<Boolean>
{
#Override
public Boolean get()
{
return false;
}
}
class StringProperty implements Property<String>
{
#Override
public String get()
{
return "hello";
}
}
class OtherStringProperty implements Property<String>
{
#Override
public String get()
{
return "bye";
}
public String getSpecialValue()
{
return "you are special";
}
}
is used by my class:
class Result<P extends Property<X>, X>
{
P p;
List<X> list;
}
As you see it has two type parameters P and X. Despite of that the X can always be deduced from P but the language requires me to supply both:
Result<BooleanProperty, Boolean> res = new Result<BooleanProperty, Boolean>();
Is there any trick to get rid of the X type parameter? I want just use
Result<BooleanProperty> res = new Result<BooleanProperty>();
Also, I don't want lose type information and use it as:
Result<OtherStringProperty> res = new Result<OtherStringProperty>();
String spec = res.p.getSpecialValue();
String prop = res.list.get(0);
I would change Result class to be something like
class Result<X> {
Property<X> property;
List<X> list;
}
I don't think the compiler can infer X from Property, as your Result class is waiting two definitions for the two generics.
You can't infer the type, but you can add an extra level of indirection:
class BoolProperty implements Property<Boolean>
{
#Override
public Boolean get()
{
return false;
}
}
class Sub<X, P extends Property<X>> {
P p;
List<X> list;
}
class Result<X> extends Sub<X, Property<X>> {
}
Result<Boolean> res = new Result<Boolean>();
List<Boolean> list = res.list;
Boolean b = res.p.get();
List<String> res2 = res.list; // compilation error
There is a similar question whose answer you might find interesting: https://stackoverflow.com/a/4452268/247763
Essentially, there's no real way to get around including the extra generic type, because the compiler can't know what type you're using without it. I'm guessing this defeats the purpose of your approach, but you could try extending Result while specifying the types - something like this:
class BoolResult extends Result<BoolProperty, Boolean> {
// Do stuff
}
Have you tried using the wildcard generic?
class Result<? extends Property<X>>
{
// stuff
}

Categories