2015-06-14 4 views
1

Я создаю программу, которая может генерировать исходный код класса, enum и интерфейсов с использованием отражения, но у меня проблема с генерацией Enum.Java reflection - enum generate

Мой EumTest класс

public enum EnumTest{ 
a,b; 

private String r; 

private EnumTest(){ 

} 

private void some(){ 

} 

public int[] some2(int[] b){ 
    return b; 
} 
} 

Метод, который генерирует ENUM файлу

private void generateEnum(Class<?> cls,PrintWriter writer) { 
    this.writePackage(cls, writer); 
    this.writeAnnotations(writer, cls.getDeclaredAnnotations()); 
    writer.write(Modifier.toString(cls.getModifiers())+ " enum " + cls.getSimpleName()); 
    this.writeImplementation(cls, writer); 
    writer.write("{"); 
    this.writeNewLine(writer); 
    Object[] cons = cls.getEnumConstants(); 
    for (int i = 0; i < cons.length; i++) { 
     writer.write(cons[i].toString()); 
     if(i != cons.length - 1) 
      writer.write(","); 
    } 
    writer.write(";"); 
    this.writeNewLine(writer); 
    this.writeFields(cls, writer); 
    this.writeConstructors(cls, writer); 
    this.writeMethods(cls,writer); 
    writer.write("}"); 
} 

Результат этот новый Enum

package metaprogramovanie.test; 
public final enum EnumTest{ 
a,b; 
private java.lang.String r; 
private static final metaprogramovanie.test.EnumTest[] $VALUES; 

private EnumTest(java.lang.String arg0,int arg1){ 
} 
public static metaprogramovanie.test.EnumTest[] values(){ 
return null; 
} 
public static metaprogramovanie.test.EnumTest valueOf(java.lang.String arg0){ 
return null; 
} 
private void some(){ 

} 
public int daco(int arg0){ 
return 0; 
} 

} 

Как вы можете видеть, что есть сом ошибки. Для примера Модификатора генерировать FINAL и перечисление не может быть окончательным, рядом есть несколько методов и полей, конструктор имеет ... Счетчик

Конструктора генерировать

private void writeConstructors(Class<?> cls, PrintWriter writer){ 
    Constructor[] cons = cls.getDeclaredConstructors(); 
    for (Constructor constructor : cons) { 
     this.writeAnnotations(writer, constructor.getDeclaredAnnotations()); 
     writer.write(Modifier.toString(constructor.getModifiers()) + " " + cls.getSimpleName()); 
     this.writeParameters(writer,constructor.getParameters()); 
     writer.write("{"); 
     this.writeNewLine(writer); 
     writer.write("}"); 
     this.writeNewLine(writer); 
    } 
} 

поля генерирует

private void writeFields(Class<?> cls, PrintWriter writer){ 
    Field[] atr = cls.getDeclaredFields(); 
    for (Field field : atr) { 
     if(field.isEnumConstant()){ 
      System.out.println("JE"); 
     } 
     else{ 
      this.writeAnnotations(writer, field.getDeclaredAnnotations()); 
      writer.write(Modifier.toString(field.getModifiers())+" " + field.getType().getTypeName()+ " " + field.getName()); 
      if(Modifier.isStatic(field.getModifiers())){ 
       try{ 
        Object value = field.get(null); 
        writer.write(" = " + this.getFieldValue(field)); 
       }catch(IllegalAccessException ex){ 

       } 
      } 
      writer.write(";"); 
      this.writeNewLine(writer); 
     } 
    } 
    this.writeNewLine(writer); 
} 

Методы генерации

private void writeMethods(Class<?> cls, PrintWriter writer){ 
    Method[] methods = cls.getDeclaredMethods(); 
    for (Method met : methods) { 
     this.writeAnnotations(writer, met.getDeclaredAnnotations()); 
     writer.write(Modifier.toString(met.getModifiers())+" "+met.getReturnType().getTypeName() +" "+ met.getName()); 
     this.writeParameters(writer, met.getParameters()); 
     writer.write("{"); 
     this.writeNewLine(writer); 
     if(!met.getReturnType().equals(Void.TYPE)){ 
      this.writeMethodBody(writer,met); 
     } 
     this.writeNewLine(writer);  
     writer.write("}"); 
     this.writeNewLine(writer); 
    } 
    this.writeNewLine(writer); 
} 

Если у вас есть идеи, как получить перечисление, которое можно скомпилировать.

+0

Откуда взялся «daco»? – RealSkeptic

+0

sry я скопирую его и переименую в stackoverflow some2 is daco, но я добавил [] не знаю, почему я его изменю – salian

ответ

1

Вот объяснение, почему вы получаете все лишние вещи.

Режимы реализованы с использованием большого количества кода, который синтезируется компилятором, так что «за кулисами» они ведут себя как спецификация языка Java, не требуя, чтобы JVM был радикально изменен.

Java Language Specification говорит, например, что:

  • enum неявно final, если нет постоянной с телом.
  • Любое enum неявно объявляет методы values() и valueOf(String).

По этой причине вы получили модификатор final для EnumTest, и вы получили два дополнительных методов.

Кроме того, компилятор синтезирует некоторый код, чтобы эффективно реализовать некоторые из необходимых материалов. Например, источник массива, который должен быть скопирован и возвращен методом values(), помещается в синтетическое поле с именем, в данном случае $VALUES. Он заполняется при инициализации перечисления, а затем его можно копировать всякий раз, когда вызывается values().

Кроме того, чтобы правильно инициализировать константы, компилятор добавляет два скрытых параметра каждому из конструкторов. Поэтому, если у вас есть пустой конструктор, за кулисами у него фактически есть два параметра - имя константы и порядковый номер. Если у вас есть конструктор с одним параметром, за кулисами у него будет 3 параметра.

Существует дополнительный синтетический код, созданный, когда у вас есть константы с их собственными телами.

Все эти последние реализации, выполненные компилятором, являются , а не, задокументированы в JLS и в основном оставлены до любого компилятора, чтобы решить, как реализовать. Пока перечисление ведет себя правильно в результате того, какой код генерирует компилятор, он может свободно генерировать его любым способом, который он выбирает.


Советов по преодолению некоторых проблем, возникавшие:

  • Вместо использования Modifier.toString(cls.getModifiers()) для печати enum модификаторов, используют

    Modifier.toString(cls.getModifiers() & ~ Modifier.FINAL & ~ Modifier.ABSTRACT) 
    

    Это исключает модификатор final из а также модификатор abstract, который будет отображаться, если вы добавите абстрактные методы в enum (и обрабатывать постоянные тела, чего вы еще не сделали).

  • Используйте метод Field.isSynthetic(), чтобы проверить, было ли поле синтезировано компилятором, и не выводить поля, для которых этот метод возвращает true. Это избавится от поля $VALUES.
  • Два метода: values() и valueOf(String) не считаются синтетическими, и если вы используете на них Method.isSynthetic(), он вернет false. Поэтому вам просто нужно проверить каждый метод, который вы найдете в перечислении. Если это один из этих двух методов, с типом подписи и возврата, как указано в JLS, пропустите их и не выведите их.

Сложная часть избавляет от двух дополнительных параметров каждого из конструкторов. В принципе, когда вы перебираете параметры конструктора, вы можете пропустить первые два параметра. Однако помнит, что это будет работать только для кода, сгенерированного компилятором Oracle, и не гарантируется в будущих версиях или любом другом компиляторе!