Eliminate type parameter of java generics - java

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
}

Related

Java: is there a way for function to allow all child class as return type using generics?

Coming across a problem that I could not make a function to allow a generic return type for all the child class of a parent class.
Is there a way to create a function that allows me to return any of these children class type base on an argument?
I have the following parent class:
abstract class Number {
int res = 1;
abstract static class Builder<T extends Builder<T>> {
int res = 100;
public T setNum(int num) {
this.res = num;
return self();
}
abstract Number build();
abstract T self();
}
Number(Builder<?> builder) {
res = builder.res;
}
}
and some children class:
class One extends Number{
private int size = 1;
static class Builder extends Number.Builder<Builder> {
private int size = -1;
public Builder setSize(int size) {
this.size = size;
return self();
}
#Override
public One build() {
return new One(this);
}
#Override
protected Builder self() {
return this;
}
}
private One(Builder builder) {
super(builder);
size = builder.size;
}
}
class Two extends Number {
private String size = String.valueOf(1);
static class Builder extends Number.Builder<Builder> {
private String size;
public Builder setSize(String size) {
this.size = size;
return self();
}
#Override
public Two build() {
return new Two(this);
}
#Override
protected Builder self() {
return this;
}
}
private Two(Builder builder) {
super(builder);
size = builder.size;
}
}
Note the parent class and child classes are not done yet, but it is going to have a similar format with just more fields so this would still apply
This is something that I want to achieve:
public <T> T loadNumber(String id) {
if (id.equals('1')) {
return new ONE.Builder.build(); // this will report error right now
}
elif (id.equals('2')) {
return new TWO.Builder.build(); // this will report error right now
}
return null;
}
The problem is that type arguments are specified by the caller. Your method
public <T> T loadNumber(String id) {
can be called like
Two two = loadNumber("One");
causing the compiler to infer
Two two = loadNumber<Two>("One");
which is why the compiler expects your method implementation to conjure a T out of thin air, and is not satisfied with a One. After all, T could stand for Two, as in the example above, and One isn't Two.
Put differently, the method signature
public <T> T loadNumber(String id) {
doesn't make sense, because the method must return a T, but has no way to determine, at runtime, what T is (due to type erasure, methods can't reflect on their type parameters).
So you have two choices:
Either you return the base type
public Number loadNumber(String id) {
and have the caller, who presumably knows which type the id he passed corresponds to, cast it to that type,
or you use an ID that whose type is itself generic and describes the type it maps to:
interface Builder<P extends Number, B extends Builder<P>> {
P build();
B self();
}
interface ID<P extends Number> {
Builder<P, ?> builder();
static ID<One> one = One.Builder::new;
static ID<Two> two = Two.Builder::new;
}
and then you can declare
public <N extends Number> N loadNumber(ID<N> id) {
return id.builder().build();
}
and use it like
One one = loadNumber(ID.one);
Two two = loadNumber(ID.two);
but not
One one = loadNumber(ID.two); // compilation error
You should be able to return any child class by simply using the parent class as a return type, in your case:
public Number loadNumber(String id) {
// your code implementation
}
Now, to save this into a variable you can use the same logic and declare the variable as the parent type. After the method returns, the variable will be casted into the whatever child class instance it returned, for example in your case:
Number obj = loadNumber("1");
The obj object will cast to an instance of One class. You can test this by printing out the object class after the above line:
System.out.println(obj.getClass());
This should print out class One or the name of whatever child class you saved into the variable.

JOOQ choose field Converter by another field

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);

Java & Type Erasure - How to generify MyClass.class from the string "MyClass"

So I have a parameterized handler type where the type is a subclass of MessageBase.
public class ResponseHandler<T extends MessageBase> {
private final T message;
private ResponseHandler(final Class<T> clazz) {
this.message = get(clazz);
}
public static <T extends MessageBase> ResponseHandler<T> of(Class<T> clazz) {
return new ResponseHandler<>(clazz);
}
private T get(Class<T> clazz) {
...
}
}
I also have a subset of DerivedMessage classes like DerivedMessage1 and DerivedMessage2 which both extend MessageBase. I want to be able to create the right ResponseHandler based on a string of the class name like this:
// defined some String s;
if (s == "com.package.DerivedMessage1") {
ResponseHandler<DerivedMessage1> h1 = ResponseHandler.of(DerivedMessage1.class);
// do something with h1
} else if (s == "com.package.DerivedMessage2") {
ResponseHandler<DerivedMessage2> h2 = ResponseHandler.of(DerivedMessage2.class);
// do something with h2
}
But I'm wondering if there's a way to do this generically for all DerivedMessage classes, which derive from MessageBase. I haven't found a way to do the DerivedMessage1.class from a string like "com.package.DerivedMessage1". I've tried Class.forName(string), but it returns a weird capture ? type that confuses me. Is there a way to accomplish this, or do I have to stick to the if statements?
you can use getCanonicalName().
For example:
DerivedMessage1.class.getCanonicalName() returns "com.package.DerivedMessage1"
so the conditions becomes
if (DerivedMessage1.class. getCanonicalName().equals(s))) {
ResponseHandler<DerivedMessage1> h1 = ResponseHandler.of(DerivedMessage1.class);
// do something with h1
}

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.

Create an enum set of generic type

How can I create an empty EnumSet when I don't have the runtime type of the generic enum? Example code:
public class Utility<T extends Enum<T>> {
private T[] enumConstants;
public Utility(Class<T> e) {
enumConstants = e.getEnumConstants();
}
private EnumSet<T> emptyEnumSet() {
// ?
}
}
Here's my current workaround, I think it comes a bit clumsy:
private EnumSet<T> emptyEnumSet() {
T first = enumConstants[0];
EnumSet<T> result = EnumSet.of(first);
result.remove(first);
return result;
}
EnumSet.noneOf() should do what you need. Your code receives the Class<T> as the constructor parameter, so you'd need to store it in a field.

Categories