2015-06-10 2 views
4

Я использую @CompileStatic в первый раз и смущен, как работают конструкторы карты Groovy в этой ситуации.Groovy's @CompileStatic и конструкторы карт

@CompileStatic 
class SomeClass { 
    Long id 
    String name 

    public static void main(String[] args) { 
     Map map = new HashMap() 
     map.put("id", 123L) 
     map.put("name", "test file") 
     SomeClass someClass1 = new SomeClass(map) // Does not work 
     SomeClass someClass2 = map as SomeClass // Works 
    } 
} 

Учитывая выше код я вижу следующее сообщение об ошибке при попытке компиляции

Groovyc: Target constructor for constructor call expression hasn't been set

Если @CompileStatic удаляется, как конструкторы работают должным образом.

Может кто-нибудь объяснить, почему new SomeClass(map) не компилируется с помощью @CompileStatic? И возможное дополнение, почему map as SomeClass все еще работает?

ответ

2

В документации CompileStatic говорит:

will actually make sure that the methods which are inferred as being called will effectively be called at runtime. This annotation turns the Groovy compiler into a static compiler, where all method calls are resolved at compile time and the generated bytecode makes sure that this happens

В результате, конструктор с картой аргументом ищется в статической компиляции в «решительности его во время компиляции», но он не нашел и таким образом, существует ошибка компиляции:

Target constructor for constructor call expression hasn't been set 

Добавление такого конструктора решает вопрос с @CompileStatic аннотацию, так как во время компиляции:

import groovy.transform.CompileStatic 

@CompileStatic 
class SomeClass { 
    Long id 
    String name 

    SomeClass(Map m) { 
     id = m.id as Long 
     name = m.name as String 
    } 

    public static void main(String[] args) { 
     Map map = new HashMap() 
     map.put("id", 123L) 
     map.put("name", "test file") 
     SomeClass someClass1 = new SomeClass(map) // Now it works also 
     SomeClass someClass2 = map as SomeClass // Works 
    } 
} 

Вы можете проверить , если хотите копать глубже.

Что касается линии

SomeClass someClass2 = map as SomeClass 

Вы используете там asType() метода Groovy's GDK java.util.Map, так что поэтому решаются во время выполнения даже в статической компиляции:

Coerces this map to the given type, using the map's keys as the public method names, and values as the implementation. Typically the value would be a closure which behaves like the method implementation.

2

Groovy на самом деле делает не податливости вы «Map-Constructor». Конструкторы в вашем классе - это то, что вы записываете. Если их нет (например, в вашем случае), , тогда есть c'tor по умолчанию.

Но что произойдет, если вы используете так называемую карту c'tor (точнее, назовите ее «строительство объекта по карте»)? Общий подход Groovy, как это:

  • создать новый объект, используя c'tor по умолчанию (это является причиной, почему строительно-на-карты больше не работает, если бы только, например, SomeClass(Long id, String name))
  • затем используйте переданную карту и примените все значения к свойствам.

Если вы disassmble кода (с @CompileDynamic (по умолчанию)) вы видите, что строительство обрабатываемого CallSite.callConstructor(Object,Object), , которая сводится к этому этим code area.

Теперь принесите в версии этой конструкции по карте, что более привычно для регулярного groovyist: SomeClass someClass3 = new SomeClass(id: 42L, name: "Douglas").

С динамической версией кода разборки этого на самом деле выглядят , как ваш код с картой. Groovy создает карту из param (s), а отправляет ее на callConstructor - так что это фактически тот же путь кода, что и (минус создание неявной карты).

Пока игнорировать «литую-дело», так как это фактически то же самое как для статического и динамического : он будет отправлен ScriptBytecodeAdapter.asType, который в основном дает динамическое поведение в любом случае.

В настоящее время @CompileStatic кейс: Как вы стали свидетелем, ваш звонок с явной картой для c'tor больше не работает. Это связано с тем, что никогда не было явного «map-c'tor» в первую очередь. Класс еще только имеет свой по умолчанию c'tor и со статической компиляцией groovyc теперь может просто работать с вещами, которые есть (или нет, если в этом случае нет).

Как насчет new SomeClass(id: 42L, name: "Douglas")? Это все еще работает со статической компиляцией! Причиной этого является то, что groovyc разворачивает этот для вас. Как вы можете видеть, это просто сводится к def o = new SomeClass(); o.setId(42); o.setName('Douglas'):

new   #2 // class SomeClass 
dup 
invokespecial #53 // Method "<init>":()V 
astore_2 
ldc2_w  #54 // long 42l 
dup2 
lstore_3 
aload_2 
lload_3 
invokestatic #45 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long; 
invokevirtual #59 // Method setId:(Ljava/lang/Long;)V 
aconst_null 
pop 
pop2 
ldc   #61 // String Douglas 
dup 
astore  5 
aload_2 
aload   5 
invokevirtual #65 // Method setName:(Ljava/lang/String;)V 
Смежные вопросы