Monday, August 17, 2020

Fixing Java Unchecked/Raw types error



https://stackoverflow.com/questions/2693180/what-is-unchecked-cast-and-how-do-i-check-it

Unchecked cast means that you are (implicitly or explicitly) casting from a generic type to a nonqualified type or the other way around. E.g. this line

Set<String> set = new HashSet();

will produce such a warning.

Usually there is a good reason for such warnings, so you should try to improve your code instead of suppressing the warning. Quote from Effective Java, 2nd Edition:

Eliminate every unchecked warning that you can. If you eliminate all warnings, you are assured that your code is typesafe, which is a very good thing. It means that you won’t get a ClassCastException at runtime, and it increases your confidence that your program is behaving as you intended.

If you can’t eliminate a warning, and you can prove that the code that provoked the warning is typesafe, then (and only then) suppress the warning with an @SuppressWarnings("unchecked") annotation. If you suppress warnings without first proving that the code is typesafe, you are only giving yourself a false sense of security. The code may compile without emitting any warnings, but it can still throw a ClassCastException at runtime. If, however, you ignore unchecked warnings that you know to be safe (instead of suppressing them), you won’t notice when a new warning crops up that represents a real problem. The new warning will get lost amidst all the false alarms that you didn’t silence.


Casts from non-generic types to generic types may work just fine at runtime, because the generic parameters are erased during compilation, so we are left with a legitimate cast. However, the code may fail later with an unexpected ClassCastException due to an incorrect assumption regarding the type parameter. For example:

    List l1 = new ArrayList();
    l1.add(33);
    List<String> l2 = (List<String>) l1;
    String s = l2.get(0);

The unchecked warning at line 3 indicates that the compiler is not able to guarantee type safety, in the sense that an unexpected ClassCastException may occur at a later point. Indeed, this happens at line 4, which performs an implicit cast.

An unchecked cast, as opposed to checked cast, does not check type safety at runtime.


https://stackoverflow.com/questions/20543966/incompatible-types-and-fresh-type-variable

[javac]   ... error: incompatible types
[javac]         exceptionClassHolder = new Holder<>( (new Exception()).getClass() );
[javac]                                ^
[javac]   required: Holder<Class<? extends Exception>>
[javac]   found:    Holder<Class<CAP#1>>
[javac]   where CAP#1 is a fresh type-variable:
[javac]     CAP#1 extends Exception from capture of ? extends Exception
[javac] 1 error

It would seem to me that the according to the message all should be correct. CAP#1 indeed extends Exception. So how should the above message be understood? SSCCE below (initially not posted since I was hoping to understand the error message itself in the general case):

class Holder<T> {
    public T t;
    public Holder(T t) {
       this.t = t;
    }
}

public class FooMain {
    public static void main(String args[]) throws Exception {
        Holder<Class<? extends Exception>> exceptionClassHolder;
        exceptionClassHolder = new Holder<>( (new Exception()).getClass() );
    }
}

Unfortunately, the existing answers don't explain what's going on here. First, the solution is to simply specify the type argument to Holder:

Holder<Class<? extends Exception>> exceptionClassHolder;
exceptionClassHolder =
        new Holder<Class<? extends Exception>>(new Exception().getClass());

The reason your version didn't work is because new Exception().getClass() returns a Class<? extends Exception>, where ? is a wildcard capture (referred to in the compiler error message as CAP#1). Since you use the "diamond operator" with new Holder<>, the compiler infers Class<CAP#1 extends Exception> for T and so Holder<Class<CAP#1 extends Exception>> is the type of the created object.

However, this doesn't match your declared type of Holder<Class<? extends Exception>>. It uses a nested wildcard, which doesn't capture: while CAP#1 extends Exception is some specific type extending Exception, the nested ? extends Exception represents literally any type extending Exception.

And while Class<CAP#1 extends Exception> is a subtype of Class<? extends Exception>Holder<Class<CAP#1 extends Exception>> is not a subtype of Holder<Class<? extends Exception>> because generics aren't covariant, so the assignment fails.

By manually specifying Class<? extends Exception> for T, you help the compiler avoid this "trap".

The problem here is that <?> represent unknown type i.e. List<?> means list of unknown type so nothing can be added to it except null as compiler can't verify the type on addition.

However, you can change the parameter type to <Integer> or <? super Integer> to make that method work:


https://stackoverflow.com/questions/7366237/mockito-stubbing-methods-that-return-type-with-bounded-wild-cards/7655709#7655709

Additional Details

To be clear, here's the observed compiler error,

The method thenReturn(List<capture#1-of ? extends Number>) in the type OngoingStubbing<List<capture#1-of ? extends Number>> is not applicable for the arguments (List<capture#2-of ? extends Number>)

I believe the compiler has assigned the first wildcard type during the when call and then cannot confirm that the second wildcard type in the thenReturn call is the same.

It looks like thenAnswer doesn't run into this issue because it accepts a wildcard type while thenReturn takes a non-wildcard type, which must be captured. From Mockito's OngoingStubbing,

OngoingStubbing<T> thenAnswer(Answer<?> answer);
OngoingStubbing<T> thenReturn(T value);
    Answer<List<Integer>> answer = setupDummyListAnswer(77, 88, 99);
    Mockito.when(dummyClass.dummyMethod()).thenAnswer(answer); 
private <N extends Number> Answer<List<N>> setupDummyListAnswer(N... values) {
    final List<N> someList = new ArrayList<N>();

    someList.addAll(Arrays.asList(values));

    Answer<List<N>> answer = new Answer<List<N>>() {
        public List<N> answer(InvocationOnMock invocation) throws Throwable {
            return someList;
        }   
    };
    return answer;
}
public static <T> Answer<T> createAnswer(final T value) {
    Answer<T> dummy = new Answer<T>() {
        @Override
        public T answer(InvocationOnMock invocation) throws Throwable {
            return value;
        }
    };
    return dummy;
}

With this helper method you could write:

Mockito.when(dummyClass.dummyMethod()).thenAnswer(createAnswer(someList));

Instead, to circumevent the compiler error described in the question, the recommended Mockito when() approach can be used with thenAnswer() and a lambda (instead of a helper method):

Mockito.when(mockedClass.mockedMethod()).thenAnswer(x -> resultList)

https://stackoverflow.com/questions/36615330/mockito-doanswer-vs-thenreturn

Answer is used when you need to do additional actions when a mocked method is invoked, e.g. when you need to compute the return value based on the parameters of this method call.

Use doAnswer() when you want to stub a void method with generic Answer.

Answer specifies an action that is executed and a return value that is returned when you interact with the mock.

@Test
public void test_answer() throws Exception {
    Dummy dummy = mock(Dummy.class);
    Answer<Integer> answer = new Answer<Integer>() {
        public Integer answer(InvocationOnMock invocation) throws Throwable {
            String string = invocation.getArgumentAt(0, String.class);
            return string.length() * 2;
        }
    };

    // choose your preferred way
    when(dummy.stringLength("dummy")).thenAnswer(answer);
    doAnswer(answer).when(dummy).stringLength("dummy");
}



 

Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts