2016-08-27 1 views
1

反射、Java8ストリーム、およびIntelliJに問題があります。IntelliJはオブジェクトを適切なクラスタイプではなくストリームで表示します

Optional<Class> optionalAnnotationClass=...; // some initialization here 
Map<Object, Object> anotherMap=new Hashmap(); 
Class sourceClass = MyClass.class;// some class 

Arrays.asList(sourceClass.getDeclaredFields()).stream() 
      .filter(field -> (!optionalAnnotationClass.isPresent() || Objects.nonNull(field.getAnnotation(optionalAnnotationClass.get())))) 
      .filter(field -> filterFieldClass.length == 0 || Arrays.asList(filterFieldClass).contains(field.getType())) 
      .map(field -> doSomething(sourceClass, field)) 
      .filter(Objects::nonNull) 
      .forEach(entry -> anotherMap.put(entry.getKey(), entry.getValue())); 

しかしIntelliJ15がライン

.filter(field -> filterFieldClass.length == 0 || Arrays.asList(filterFieldClass).contains(field.getType())) 
のように、それは、 fieldObjectではなく最初の filter後に開始 Fieldであることを訴えて開始し、次のメッセージ

enter image description here

で私を悩まします

プロジェクトのバージョンを確認しましたが、それはウィットです1.8をターゲットとし、JDK8を使用します。キャッシュを無効にしてIntelliJを再起動しました。

どういうところが間違っていますか?


は、ここで私は、最初のフィルタは、JDKに好かれていない理解していない、このような理由から完全

package com.ladop; 

import com.google.common.base.CaseFormat; 
import com.google.common.collect.Maps; 

import java.lang.reflect.Field; 
import java.util.Arrays; 
import java.util.HashMap; 
import java.util.Map; 
import java.util.Objects; 
import java.util.Optional; 

import static com.google.common.base.Preconditions.checkArgument; 

public class StaticReflectionUtils { 

    public static Map<String, Object> extractStaticField(final Class<?> sourceClass, 
                 final Optional<Class> optionalAnnotationClass, 
                 final Class<?>... filterFieldClass) { 
     final Map<String, Object> fieldNameToValue = new HashMap<>(); 
     Arrays.stream(sourceClass.getDeclaredFields()) 
       .filter(field -> !optionalAnnotationClass.isPresent() || Objects.nonNull(field.getAnnotation(optionalAnnotationClass.get()))) 
       .filter(field -> filterFieldClass.length == 0 || Arrays.asList(filterFieldClass).contains(field.getType())) 
       .map(field -> extractFieldKeyValue(sourceClass, field)) 
       .filter(Objects::nonNull) 
       .forEach(entry -> fieldNameToValue.put(entry.getKey(), entry.getValue())); 
     return fieldNameToValue; 
    } 

    public static Map.Entry<String, Object> extractFieldKeyValue(final Class<?> sourceClass, 
                   final Field field) { 
     field.setAccessible(true); 
     try { 
      final String fieldName = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, field.getName()); 
      return Maps.immutableEntry(
        concatenate(sourceClass.getSimpleName(), fieldName), field.get(null)); 
     } catch (IllegalAccessException e) {     
     } 
     return null; 
    } 

    protected static String concatenate(final String prefix, final String word) { 
     return new StringBuilder() 
       .append(prefix) 
       .append("_") 
       .append(word).toString(); 
    } 

} 
+0

IJとは対照的に永続的なビルドツールを使用するとコンパイルできますか?そうでない場合、コードは間違っています。おそらく、あなたはsourceClassのタイプとしてClass を意味するでしょうか? – bmargulies

+0

@bmargulies良い提案。コマンドラインでmvn clean installを実行すると、同じエラーが発生するので、IntelliJではありません。 sourceClassのタイプが重要なのはなぜですか?私はフィールドを抽出し、それらを反復処理しています。 –

+0

@bmarguliesが固定されています(回答を参照)。しかし、私は何が問題なのか理解できません! JDKの問題? –

答えて

4

まず、HashMap<>()に変更Hashmap()、及び...を:のように定義された方法と

Arrays.asList(sourceClass.getDeclaredFields()).stream() 
      .filter(field -> hasAnnotationIfPresent(field, optionalAnnotationClass)) 
      .filter(field -> filterFieldClass.length == 0 || Arrays.asList(filterFieldClass).contains(field.getType())) 
      .map(field -> doSomething(sourceClass, field)) 
      .filter(Objects::nonNull) 
      .forEach(entry -> anotherMap.put(entry.getKey(), entry.getValue())); 

Arrays.asList(sourceClass.getDeclaredFields()).stream() 
      .filter(field -> (!optionalAnnotationClass.isPresent() || Objects.nonNull(field.getAnnotation(optionalAnnotationClass.get())))) 
      .filter(field -> filterFieldClass.length == 0 || Arrays.asList(filterFieldClass).contains(field.getType())) 
      .map(field -> doSomething(sourceClass, field)) 
      .filter(Objects::nonNull) 
      .forEach(entry -> anotherMap.put(entry.getKey(), entry.getValue())); 

:から 。

第二に、あなたの例ではMinimal, Complete, and Verifiableするいくつかの宣言が欠落しているので、私はテストのためにこれを追加しました:

private static class MyClass {} 
private static Class<?>[] filterFieldClass = {}; 
private static Map.Entry<Object, Object> doSomething(Class<?> sourceClass, Field field) { 
    return null; 
} 

そして、すべて消えてコンパイルエラーを!あなたのコードがコンパイルされない場合(jdk1.8.0_91)

だから、私が想定し3つの宣言は異なり、あなたのコードで入力されています。ほとんどの場合、doSomething()は異なるタイプを取るか、返します。

更新日: Eclipseが正常にコンパイルされます。 javac 1.8.0_91でコンパイルすると、エラーが発生します。これは、以下で説明するように、未処理のタイプを修正することで解消されます。
私はEclipseコンパイラが良いと思います。(?)は、Oracleコンパイラよりもlambdaを推測しています。サイドノートでは


、あなたのコードは、タイプを使用しています。 しないでください!以下を変更し

  • Optional<Class>Optional<Class<? extends Annotation>>
  • Class sourceClassClass<?> sourceClass

にまた、Arrays.asList(...).stream()Arrays.stream(...)する必要があります。

+0

フルクラスを付けました。私はまた提案されたようにストリームを置き換えました。 –

+0

問題は、オプションの未処理の型にありました。なぜそれが機能していなかったのか説明できますか? –

+0

生の型が使用されると(適用性のためにチェックされていない変換が強制されると)、推定された署名も消去されます。したがって、Objectの使用。これは、タイプ引数の欠如が、推論結果がもはや正確に信頼されることができないことを意味するために行われます。 –

0

のために、完全なコードです。私は式をメソッドにラップすることでそれを変更しました。コンパイル可能コードのOptional.empty()

private static boolean hasAnnotationIfPresent(final Field field, final Optional<Class> optionalAnnotationClass) { 
    return !optionalAnnotationClass.isPresent() || Objects.nonNull(field.getAnnotation(optionalAnnotationClass.get())); 
} 
関連する問題