Como evitar o plugin Scala 0.19.297 para o Idea 12.1.4 Spring framework trap

O novo plugin Scala introduz uma regressão na compilação de classes Java que pode fazer você perder dias para resolver. Se você usar injeção de construtor Spring Framework , provavelmente encontrará este problema

O fundo

Se você usa injeção de construtor Spring Framework, pode usar sem saber o que está acontecendo nos bastidores.

Já que o nome dos parâmetros é apagado durante a compilação, o Spring usa essas informações para criar o link entre o nome do construtor-arg em seu contexto e os argumentos do construtor . Para que esse mecanismo funcione, as informações de depuração corretas sobre vars devem ser produzidas pelo compilador.

É assim que a classe aparecerá se esta informação for produzida e você desmontar com javap -cv


public class MyClass extends java.lang.Object
SourceFile: "MyClass.java"
minor version
: 0
major version
: 49
Constant pool:
const #1 = Method #6.#24; // java/lang/Object."<init>":()V
const #2 = Field #5.#25; // MyClass.myEnum:LMyEnum;
const #3 = Field #5.#26; // MyClass.ok:Z
const #4 = Field #5.#27; // MyClass.good:Z
const #5 = class #28; // MyClass
const #6 = class #29; // java/lang/Object
const #7 = Asciz myEnum;
const #8 = Asciz LMyEnum;;
const #9 = Asciz ok;
const #10 = Asciz Z;
const #11 = Asciz good;
const #12 = Asciz <init>;
const #13 = Asciz (LMyEnum;ZZ)V;
const #14 = Asciz Code;
const #15 = Asciz LineNumberTable;
const #16 = Asciz LocalVariableTable;
const #17 = Asciz this;
const #18 = Asciz LMyClass;;
const #19 = Asciz isOk;
const #20 = Asciz ()Z;
const #21 = Asciz isGood;
const #22 = Asciz SourceFile;
const #23 = Asciz MyClass.java;
const #24 = NameAndType #12:#30;// "<init>":()V
const #25 = NameAndType #7:#8;// myEnum:LMyEnum;
const #26 = NameAndType #9:#10;// ok:Z
const #27 = NameAndType #11:#10;// good:Z
const #28 = Asciz MyClass;
const #29 = Asciz java/lang/Object;
const #30 = Asciz ()V;

{
public MyClass(MyEnum, boolean, boolean);
Code:
Stack=2, Locals=4, Args_size=4
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: aload_1
6: putfield #2; //Field myEnum:LMyEnum;
9: aload_0
10: iload_2
11: putfield #3; //Field ok:Z
14: aload_0
15: iload_3
16: putfield #4; //Field good:Z
19: return
LineNumberTable:
line
12: 0
line
13: 4
line
14: 9
line
15: 14
line
16: 19

LocalVariableTable:
Start Length Slot Name Signature
0 20 0 this LMyClass;
0 20 1 myEnum LMyEnum;
0 20 2 ok Z
0 20 3 good Z


public boolean isOk();
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: getfield #3; //Field ok:Z
4: ireturn
LineNumberTable:
line
19: 0

LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LMyClass;


public boolean isGood();
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: getfield #4; //Field good:Z
4: ireturn
LineNumberTable:
line
23: 0

LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LMyClass;


}

O problema

Se você criar um projeto Java Maven simples , tudo funcionará bem no Idea 12.1.4. No entanto, se você adicionar Scala e usar a última versão do plugin, LocalVariableTable não é gerado para classes Java.

Como resultado, seu aplicativo que estava funcionando, não está mais funcionando e durante a instanciação dos beans, o Spring lançará uma exceção idiota com a mensagem inútil:

Tipos de argumento do construtor ambíguos – você especificou as referências de bean corretas como argumentos do construtor?

A solução

Confiar na leitura de classe não é a única maneira de realizar injeção de construtor no Spring: há uma solução alternativa, uma anotação chamada ConstructorProperties que você pode usar da seguinte maneira:


@ConstructorProperties({"currency","startCurrency","refreshQuotesAtStartup"})
public CurrencyStartupConfiguration(Currency currency, boolean startCurrency, boolean refreshQuotesAtStartup) {
this.currency = currency;
this.startCurrency = startCurrency;
this.refreshQuotesAtStartup = refreshQuotesAtStartup;
}