Compilation error with Optional in generic class - java

I have an unexplained compilation error with guava Optional I have this test for demonstrate :
package com.livingobjects.pmin.test;
import com.google.common.base.Optional;
import org.junit.Test;
public class OptionalTest {
public class ContainOptional<T> {
T id;
Optional<String> label;
public ContainOptional(T id, Optional<String> label) {
this.id = id;
this.label = label;
}
public T getId() {
return id;
}
public Optional<String> getLabel() {
return label;
}
}
#Test
public void shouldGetOptional() throws Exception {
ContainOptional co = new ContainOptional<>(42, Optional.of("H2G2"));
String label = co.getLabel().get(); // Can not compile
Optional<String> opt = co.getLabel(); // Can
String labelOpt = opt.get(); // compile
}
}
When I try to get Optional from a container generic object I need to use intermediate variable instead of inline code.
When I use chain call of co.getLabel().get(); the Optional.get return Object instead of String ?
EDIT: I use Guava 17.0 and Java 1.7.0_51

In the line
ContainOptional co = new ContainOptional<>(42, Optional.of("H2G2"));
ContainOptional should have a parameter but doesn't, so the compiler ignores all generics on that class and uses Object everywhere. Write:
ContainOptional<Integer> co = new ContainOptional<>(42, Optional.of("H2G2"));
and it should work. (Integer being the type of 42).

Related

Why is Kotlins type inference failing when Javas isn't?

Given the following code (which uses a dummy return but shows the issue):
import com.github.roookeee.datus.api.Datus
import com.github.roookeee.datus.api.Mapper
import com.github.roookeee.datus.immutable.ConstructorParameter
data class EntryDto(val id: Long?, val title: String, val content: String)
data class EntryEntity(val id: Long? = null, val title: String, val content: String) {
fun toDto(): EntryDto {
val mapper: Mapper<EntryEntity, EntryDto> = Datus.forTypes(this.javaClass, EntryDto::class.java)
.immutable(::EntryDto)
.from(EntryEntity::id).to(ConstructorParameter::bind)
.from(EntryEntity::title).to(ConstructorParameter::bind)
.from(EntryEntity::content).to(ConstructorParameter::bind)
.build()
return EntryDto(null, "", "")
}
}
Kotlin is not able to infer the correct generic types whereas Java >= 8 does (given two Java classes that are identical to the data classes here - two immutable object classes). I tried with the defaults for Kotlin 1.3.0 and -XXLanguage:+NewInference but the later couldn't even infer the right overload to pick for .immutable.
Here is the datus dependency information to make the above code compile (I can't reduce this problem without the library, it's too complex in its generic usage):
<dependency>
<groupId>com.github.roookeee</groupId>
<artifactId>datus</artifactId>
<version>1.3.0</version>
</dependency>
Am I missing something? I would love to make my library more compatible with kotlin but am at a loss how to go from here or what the exact name of the inference error is.
You can find datus sources here.
This is the corresponding java code:
import com.github.roookeee.datus.api.Datus;
import com.github.roookeee.datus.api.Mapper;
import com.github.roookeee.datus.immutable.ConstructorParameter;
class Java8Code {
static class EntryDto {
private final Long id;
private final String title;
private final String content;
EntryDto(Long id, String title, String content) {
this.id = id;
this.title = title;
this.content = content;
}
public Long getId() {
return id;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
}
static class EntryEntity {
private final Long id;
private final String title;
private final String content;
EntryEntity(Long id, String title, String content) {
this.id = id;
this.title = title;
this.content = content;
}
public Long getId() {
return id;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
public EntryDto toDto() {
Mapper<EntryEntity, EntryDto> mapper = Datus.forTypes(EntryEntity.class, EntryDto.class)
.immutable(EntryDto::new)
.from(EntryEntity::getId).to(ConstructorParameter::bind)
.from(EntryEntity::getTitle).to(ConstructorParameter::bind)
.from(EntryEntity::getContent).to(ConstructorParameter::bind)
.build();
return mapper.convert(this);
}
}
}
EDIT 2: An image of the error message + some notes below
3 type arguments expected for interface ConstructorParameter<In : Any!, GetterReturnType : Any!, Result : Any!> - Kotlin seems to expect generic type parameters for the interfaces method reference but that simply isn't possible in Kotlin nor needed in Java.
The to extension function is not the problem. It just pops up because the compiler does not see the correct parameter for the member method.
What Kotlin doesn't like, is the generic type without the type parameter attached. ConstructorParameter is not a type until you specify the type parameters. So it complains when it sees ConstructorParameter::bind, the left hand side of :: should be a type.
If you write .to { x, y -> x.bind(y) }, Kotlin can infer the type just fine.
But you can't expect your users to write this "same" lambda so many times.
Extension functions to the rescue!
fun <In, CurrentType, Next> ConstructorParameterBinding<In, CurrentType, out ConstructorParameter<In, CurrentType, Next>>.bind(): Next =
this.to { x, y -> x.bind(y) }
val mapper: Mapper<EntryEntity, EntryDto> = Datus.forTypes(this.javaClass, EntryDto::class.java)
.immutable(::EntryDto)
.from(EntryEntity::id).bind()
.from(EntryEntity::title).bind()
.from(EntryEntity::content).bind()
.build()

Using Java 8 is there a way to validate/assert that a constant is a compile-time constant?

I'd like to have a JUnit test that verifies a specific constant is a Compile-Time Constant.
How would I go about doing that?
I found a solution for Scala, but I'd like on for plain Java.
Is there a way to test at compile-time that a constant is a compile-time constant?
Root Cause:
The value for annotation attribute ApiModelProperty.allowableValues must be a constant expression
What I'd like in a Unit Test:
validateCompileTimeConstant(SomeClass.CONSTANT_VALUE, "Message Here!!");
Usage
#ApiModelProperty(name = "name", required = true, value = "Name", allowableValues=SomeClass.API_ALLOWABLE_VALUES, notes=SomeClass.API_NOTES)
private String name;
SomeClass
public enum SomeClass {
BOB(4, "Bob"),//
TED(9, "Ted"),//
NED(13, "Ned");
public static final String API_ALLOWABLE_VALUES = "4,9,13,16,21,26,27,170";
public static final String API_NOTES = "4 - Bob\n" +
"9 - Ted\n" +
"13 - Ned";
public int code;
public String desc;
private ContentCategoryCode(int code, String desc) {
this.code = code;
this.desc = desc;
}
public static final String apiAllowableValues() {
StringBuilder b = new StringBuilder();
for (ContentCategoryCode catCode : values()) {
b.append(catCode.code);
b.append(',');
}
b.setLength(b.length()-1);
return b.toString();
}
public static final String apiNotes() {
StringBuilder b = new StringBuilder();
for (ContentCategoryCode catCode : values()) {
b.append(catCode.code).append(" - ").append(catCode.desc);
b.append('\n');
}
b.setLength(b.length()-1);
return b.toString();
}
}
The Error Prone project has a #CompileTimeConstant annotation which can be used to enforce exactly this.
It's not a test that you run with JUnit, but a compiler plug-in that enforces this (and other bug patterns) at compile time.
Here is the documentation: https://errorprone.info/bugpattern/CompileTimeConstant
I ended up creating my own annotation, since it required less setup than using Error Prone.
Annotation Class:
#Target(ElementType.METHOD)
public #interface TestCompileTimeConstant {
public String key() default "";
}
JUnit Test:
public class SomeClassTest {
#Test
public void test() {
assertEquals(SomeClass.API_ALLOWABLE_VALUES, SomeClass.apiAllowableValues());
assertEquals(SomeClass.API_NOTES, SomeClass.apiNotes());
}
#Test
#TestCompileTimeConstant(key=SomeClass.API_ALLOWABLE_VALUES)
public void testIsCompileTimeConstant1() {
//Pass - If this doesn't compile, you need to make sure API_ALLOWABLE_VALUES doesn't call any methods.
}
#Test
#TestCompileTimeConstant(key=SomeClass.API_NOTES)
public void testIsCompileTimeConstant2() {
//Pass - If this doesn't compile, you need to make sure API_NOTES doesn't call any methods.
}
}

Why does IntelliJ tell me that my class never returns null?

private void addCompoundsFrom(Verse verse) {
Optional<List<Compound>> compounds = Optional.of(verse.getCompounds());
if (compounds.isPresent()) {
for (Compound compound : compounds.get()) {
addCompoundsFrom(compound);
}
}
}
The IntelliJ inspector tells me that the if-statement is always true. How can it know that? This is the Compounds class:
public class Compounds extends PositionalIds {
#XmlElement(name = "verse")
private List<Verse> verses;
public List<Verse> getVerses() {
return verses;
}
}
#XmlTransient
public abstract class PositionalIds {
#XmlAttribute(name = "start")
private String startId;
#XmlAttribute(name = "end")
private String endId;
public String getStartId() {
return startId;
}
public String getEndId() {
return endId;
}
}
And the Verse class:
public class Verse extends PositionalIds {
#XmlElement(name = "compound")
private List<Compound> compounds;
#XmlAttribute(name = "notation")
private String notation;
public List<Compound> getCompounds() {
return compounds;
}
public String getNotation() {
return notation;
}
}
If I stop using Optional to wrap the verse.getCompounds() result and instead just do a null check, the inspection message goes away.
I'm using Java 8.
The Optional class has two methods:
Optional.of -> throws exception if the parameter is null
Optional.ofNullable -> creates an empty optional if the parameter is null
Hence if your method returns null, the of() method will throw an exception and empty optional will never reach your if statement
Optional.of(verse.getCompounds()); returns an Optional that contains a valid value.
The isPresent check that follows will always be true because the Optional compounds will never not have a value, since you just set it to a valid value on the line above.

what is IntegerProperty and why does it need to be imported

So in class we always use the following syntax. Correct me if i am wrong but this is a bean because it class use getters/setters. It has an nullary constructor and the class implements serializable.
// option 1
private int customerID ;
public CustomerDTO ()
{
this(0);
}
public CustomerDTO(int customerID) {
setCustomerID(customerID);
}
public void setCustomerID(int customerID) {
this.customerID = customerID;
}
public int getCustomerID() {
return customerID;
}
But today i came across something similar like this. i needed to import
import javafx.beans.property.SimpleStringProperty;
But what is the main difference between option 1 and 2.
When should i use option 1 or option 2
And which one is better or does it depends on the situation.
// option 2
private final IntegerProperty customerID;
public CustomerDTO ()
{
this(null);
}
public CustomerDTO(IntegerProperty customerID) {
this.customerID = new SimpleIntegerProperty();
}
public IntegerProperty getCustomerID() {
return customerID;
}
public void setCustomerID(int customerID) {
this.customerID.set(customerID);
}
Option 2 is used when you are building JavaFX application and want to bind your model with gui.
Example:
public class Foo {
private final StringProperty foo = new SimpleStringProperty();
public String getFoo() {
return foo.get();
}
public StringProperty fooProperty() {
return foo;
}
public void setFoo(String foo) {
this.foo.set(foo);
}
}
public class FooController {
#FXML
private TextField fooTextField;
private final Foo foo = new Foo();
#FXML
public void initialize() {
foo.fooProperty().bindBidirectional(fooTextField.textProperty());
}
}
public CustomerDTO(IntegerProperty customerID) { makes no sense, a property is a final class member which encapsulates a value, this value can be set via setters and get via setters, in JavaFX controller classes it is advisable to also implement a getter for the ReadOnlyObjectProperty or ReadOnlyIntegerProperty in your case, this can be done via ReadOnlyIntegerWrapper and its getReadOnlyProperty method. This enables the developor to bind to values from other classes whilst also ensuring that the value exists at any time, JavaFX Bindings are a pretty elegant and object-oriented method of data-encapsulation.
Your "option 2" actually is flawed since it allows property-redefinition which breaks this concept and makes the property itself useless. It will also break GUI functionality except if the property itself can not be redefined, see the accepted answer

Fetch first element of stream matching the criteria

How to get first element that matches a criteria in a stream? I've tried this but doesn't work
this.stops.stream().filter(Stop s-> s.getStation().getName().equals(name));
That criteria is not working, the filter method is invoked in an other class than Stop.
public class Train {
private final String name;
private final SortedSet<Stop> stops;
public Train(String name) {
this.name = name;
this.stops = new TreeSet<Stop>();
}
public void addStop(Stop stop) {
this.stops.add(stop);
}
public Stop getFirstStation() {
return this.getStops().first();
}
public Stop getLastStation() {
return this.getStops().last();
}
public SortedSet<Stop> getStops() {
return stops;
}
public SortedSet<Stop> getStopsAfter(String name) {
// return this.stops.subSet(, toElement);
return null;
}
}
import java.util.ArrayList;
import java.util.List;
public class Station {
private final String name;
private final List<Stop> stops;
public Station(String name) {
this.name = name;
this.stops = new ArrayList<Stop>();
}
public String getName() {
return name;
}
}
This might be what you are looking for:
yourStream
.filter(/* your criteria */)
.findFirst()
.get();
And better, if there's a possibility of matching no element, in which case get() will throw a NPE. So use:
yourStream
.filter(/* your criteria */)
.findFirst()
.orElse(null); /* You could also create a default object here */
An example:
public static void main(String[] args) {
class Stop {
private final String stationName;
private final int passengerCount;
Stop(final String stationName, final int passengerCount) {
this.stationName = stationName;
this.passengerCount = passengerCount;
}
}
List<Stop> stops = new LinkedList<>();
stops.add(new Stop("Station1", 250));
stops.add(new Stop("Station2", 275));
stops.add(new Stop("Station3", 390));
stops.add(new Stop("Station2", 210));
stops.add(new Stop("Station1", 190));
Stop firstStopAtStation1 = stops.stream()
.filter(e -> e.stationName.equals("Station1"))
.findFirst()
.orElse(null);
System.out.printf("At the first stop at Station1 there were %d passengers in the train.", firstStopAtStation1.passengerCount);
}
Output is:
At the first stop at Station1 there were 250 passengers in the train.
When you write a lambda expression, the argument list to the left of -> can be either a parenthesized argument list (possibly empty), or a single identifier without any parentheses. But in the second form, the identifier cannot be declared with a type name. Thus:
this.stops.stream().filter(Stop s-> s.getStation().getName().equals(name));
is incorrect syntax; but
this.stops.stream().filter((Stop s)-> s.getStation().getName().equals(name));
is correct. Or:
this.stops.stream().filter(s -> s.getStation().getName().equals(name));
is also correct if the compiler has enough information to figure out the types.
I think this is the best way:
this.stops.stream().filter(s -> Objects.equals(s.getStation().getName(), this.name)).findFirst().orElse(null);

Categories

Resources