简体   繁体   中英

why com.fasterxml.jackson.core.type.TypeReference implements Comparable interface?

why com.fasterxml.jackson.core.type.TypeReference implements Comparable interface? I don't understand the intention of implementing it.

public abstract class TypeReference<T> implements Comparable<TypeReference<T>>
{
    protected final Type _type;
    
    protected TypeReference()
    {
        Type superClass = getClass().getGenericSuperclass();
        if (superClass instanceof Class<?>) { // sanity check, should never happen
            throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");
        }
        /* 22-Dec-2008, tatu: Not sure if this case is safe -- I suspect
         *   it is possible to make it fail?
         *   But let's deal with specific
         *   case when we know an actual use case, and thereby suitable
         *   workarounds for valid case(s) and/or error to throw
         *   on invalid one(s).
         */
        _type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
    }

    public Type getType() { return _type; }
    
    /**
     * The only reason we define this method (and require implementation
     * of <code>Comparable</code>) is to prevent constructing a
     * reference without type information.
     */
    @Override
    public int compareTo(TypeReference<T> o) { return 0; }
    // just need an implementation, not a good one... hence ^^^
}

Here's the source code description, but I still can't understand it.

TL;DR: It does nothing and is a bug.

Did you read the source code? Because it explains it quite well.

Specifically, it links to Neal Gafter's post on Super Type Tokens and explicitly explains that the Comparable stuff is there 'inspired by a comment'. So, open that link, scroll down to the comments, and sure enough:

Brian Oxley said... Rather than check for a type parameter in the constructor, you can make it a syntax error to leave out:

 public abstract TypeReference<R> implements Comparable<TypeReference<R>> { //... public int compareTo(TypeReference<R> o) { // Need a real implementation. // Only saying "return 0" for illustration. return 0; } }

Now this is legal:

new TypeReference<Object>() { };

But this is a syntax error for not implementing Comparable :

new TypeReference() { } ;

February 20, 2007 6:12 AM

However , that is incorrect .

It actually does nothing. Here, let's try it:

> cat Test.java
import java.lang.reflect.*;
abstract class TypeReference<T> implements Comparable<TypeReference<T>> {
  protected final Type _type;
  protected TypeReference() {
    Type superClass = getClass().getGenericSuperclass();
    if (superClass instanceof Class<?>) { // sanity check, should never happen
      throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");
    }
    _type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
  }

  @Override public int compareTo(TypeReference<T> o) { return 0; }

  public static void main(String[] args) {
    TypeReference raw = new TypeReference() {};
  }
}

> javac Test.java

See? Compiles fine. If you run it, you get that 'sanity check' exception. The comparator stuff does nothing.


EDIT:

I filed a bug over at jackson about it Issue #697 .

To try to explain what the thought behind all this was (even though it does not work):

A raw type is infectious, and all aspects related to it are also raw. Raw types behaviour in unique ways, but usually those ways are very similar to having Object for all type variables, even if there is a lower bound.

Thus, new TypeReference() {} , being raw, means the Comparable it implements is also raw, which acts as if it's like Object, which means that the impl must have the method public int compareTo(Object o) .

The provided implementation of TypeReference does not have int compareTo(Object) , it only has compareTo(TypeReference) , therefore, new TypeReference() {} wouldn't compile.

A nice story. But that's not how javac works, unfortunately. You can see the logic and it makes some sense, but unfortunately that compareTo , because it matches the lower bound, gets a synthetic additional method. You can check this: If you javap TypeReference:

> javap TypeReference
javap TypeReference
Compiled from "Test.java"
abstract class TypeReference<T> implements java.lang.Comparable<TypeReference<T>> {
  protected final java.lang.reflect.Type _type;
  protected TypeReference();
  public int compareTo(TypeReference<T>);
  public static void main(java.lang.String[]);
  public int compareTo(java.lang.Object);

Note how there are two compareTo methods in the class file even though we wrote only one in the source. Thus, any classes that extends TypeReference will always have, baked in, an impl for compareTo(Object) no matter what you try to hack with the generics part of it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM