Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Заменить байткод в рантайме 
:(
    Опции темы
Foror
Дата 2.5.2009, 07:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 14.2.2004

Репутация: 1
Всего: 2



Делаю один open-source проект для веб-разработчиков и столкнулся с проблемой, что я плохо разбираюсь с генерацией байткода через javassist, asm. etc. Мне нужно в одном классе заменить у поля тип (там интерфейс SecurityAccount<SomeType, SomeSomeType>). Нужно интерфейс заменить на класс (не обязательно generic). Попробовал javassist - field.setType(). Вроде получилось, но hibernate3 так и не смог увидеть это изменение. Hibernate3 при маппинге вызывает field.getGenericType() (а не field.getType()), который возвращает generic интерфейс SecurityAccount<SomeType, SomeSomeType>. 

Вчитался подробнее в javassist документацию и выяснилось, что он не умеет работать с generic'ами. Поискал еще высокоуровневые библиотеки, которые умеют устанавливать generic типы, но так и не нашел. Сейчас вот буду разбираться с ASM.

Собственно мне также можно в рантайме добавить аннотацию @Target(Class) на SecurityAccount<SomeType, SomeSomeType> поле. Но в javassist не удалось найти как это сделать. 

Собственно, может кто разбирается как мне изменить тип (чтобы getGenericType() возвращал именно его) или добавить аннотацию в рантайме (на ASM, BCEL, javassis или любой другой либе)? А я вам клёвый open-source проект сделаю, типа spring, но клёвее smile
--------------------
Разработка веб-сайтов и создание интернет магазина
PM MAIL WWW ICQ   Вверх
ivg
Дата 2.5.2009, 23:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Autonomous R&D
**


Профиль
Группа: Участник
Сообщений: 686
Регистрация: 8.2.2006
Где: Екатеринбург

Репутация: 32
Всего: 81



Цитата(Foror @  2.5.2009,  09:27 Найти цитируемый пост)
Мне нужно в одном классе заменить у поля тип (там интерфейс SecurityAccount<SomeType, SomeSomeType>). Нужно интерфейс заменить на класс

Плохая идея. Возьмите класс, в котором есть код и чтения и записи поля (а это почти любой класс), измените тип этого поля, попытайтесь скомпилировать. А теперь представьте что будет в рантайме. Скорей всего верификатор байт-кода не пропустит. Ну а в худшем случае можно получить непонятные ошибки с приведением типов.
PM MAIL   Вверх
Foror
Дата 3.5.2009, 12:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 14.2.2004

Репутация: 1
Всего: 2



Даже если класс наследует этот интерфейс? А как насчёт добавления аннотации в рантайме на нужное поле? Кто-нибуль знает как это сделать?
--------------------
Разработка веб-сайтов и создание интернет магазина
PM MAIL WWW ICQ   Вверх
Tony
Дата 4.5.2009, 11:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1159
Регистрация: 3.3.2006
Где: Riga

Репутация: 6
Всего: 12



Цитата(Foror @  3.5.2009,  12:35 Найти цитируемый пост)
А как насчёт добавления аннотации в рантайме на нужное поле? Кто-нибуль знает как это сделать? 

Через рефлексию. Я так на ходу добовлял проперти к классу.

Это сообщение отредактировал(а) Tony - 4.5.2009, 11:15


--------------------
user posted image
user posted image
PM MAIL Skype   Вверх
ivg
Дата 4.5.2009, 11:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Autonomous R&D
**


Профиль
Группа: Участник
Сообщений: 686
Регистрация: 8.2.2006
Где: Екатеринбург

Репутация: 32
Всего: 81



Цитата(Tony @  4.5.2009,  13:14 Найти цитируемый пост)
Через рефлексию. Я так на ходу добовлял проперти к классу.

Интересно. А код не покажете?
PM MAIL   Вверх
Foror
Дата 4.5.2009, 13:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 14.2.2004

Репутация: 1
Всего: 2



Покажите пожалуйста код добавления аннотации в рантайме. Из-за этой штуки весь проект стопанулся, и времени как-то нет разобраться с ASM...
--------------------
Разработка веб-сайтов и создание интернет магазина
PM MAIL WWW ICQ   Вверх
Tony
  Дата 4.5.2009, 14:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1159
Регистрация: 3.3.2006
Где: Riga

Репутация: 6
Всего: 12



Код

DynaProperty[] properties = {
                new DynaProperty("loginDate", Date.class),
                new DynaProperty("name", String.class),
                new DynaProperty("password", String.class),
                new DynaProperty("my", String.class), };

        BasicDynaClass userDynaClass = new BasicDynaClass("User", null,
                properties);

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("name", "jason");
        map.put("password", "secret");
        map.put("loginDate", new Date());
        map.put("my", "Yo yo");
        try {
            DynaBean user = userDynaClass.newInstance();
            BeanUtils.populate(user, map);
            System.out.println(BeanUtils.getProperty(user, "my")); // displays 'Yo yo'
        } catch (Exception e) {
            e.printStackTrace();
        }

Правда тут делается копия обьекта! Про анотации, меня самого тема заинтересовала. Я думаю надо использовать ASM/CGlib (хотя он базируется на АСМе). Вот тут пример работы с аннотациями:
статья. Надеюсь статья поможет в борьбе с этой проблемой!

Это сообщение отредактировал(а) Tony - 4.5.2009, 14:45


--------------------
user posted image
user posted image
PM MAIL Skype   Вверх
Foror
Дата 4.5.2009, 16:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 14.2.2004

Репутация: 1
Всего: 2



Ага, смотрел эту статью, только ничего там не понятно smile Видимо на выходных буду разбираться с ASM, выложу код с пояснениями как сделаю.
--------------------
Разработка веб-сайтов и создание интернет магазина
PM MAIL WWW ICQ   Вверх
ivg
Дата 11.5.2009, 00:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Autonomous R&D
**


Профиль
Группа: Участник
Сообщений: 686
Регистрация: 8.2.2006
Где: Екатеринбург

Репутация: 32
Всего: 81



Код

package com.test;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;

public class Main {

    @MyAnnotation(value = "test", zz = {void.class, int.class}, ii=1)
    String field;
    
    public static void main(String[] args) throws Exception {
        TransformClassLoader tcl = TransformClassLoader.createTransformLoader();
        AddFieldAnnoClassTransformer tr = new AddFieldAnnoClassTransformer();
        tr.addTargetField("targetField", Main.class.getDeclaredFields()[0].getAnnotations()[0]);
        tcl.addTransformer(Test.class.getName(), tr);
        Class<?> clazz = tcl.loadClass(Test.class.getName());
        System.out.println(clazz);
        System.out.println(clazz == Test.class);
        System.out.println(Arrays.toString(Test.class.getDeclaredFields()[0].getAnnotations()));
        System.out.println(Arrays.toString(clazz.getDeclaredFields()[0].getAnnotations()));
    }
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface MyAnnotation {
    String value();
    Class<?>[] zz() default {};
    int[] ii();
}

class Test {
    String targetField;
}

Код

package com.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;

interface ClassTransformer extends ClassVisitor {
    public void setTargetVisitor(ClassVisitor cv);
}

public final class TransformClassLoader extends ClassLoader {

    public static TransformClassLoader createTransformLoader() {
        return createTransformLoader(null);
    }

    public static TransformClassLoader createTransformLoader(final ClassLoader source) {
        ClassLoader parent = source;
        if (parent == null) {
            parent = Thread.currentThread().getContextClassLoader();
            if (parent == null) {
                parent = TransformClassLoader.class.getClassLoader();
            }
        }
        return new TransformClassLoader(parent);
    }

    private Map<String, ClassTransformer> transformers;

    private TransformClassLoader(ClassLoader parent) {
        super(parent);
        this.transformers = new HashMap<String, ClassTransformer>();
    }

    @Override
    protected synchronized Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException {

        Class<?> c = super.findLoadedClass(name);
        if (c == null) {
            ClassTransformer tr = this.transformers.get(name);
            if (tr == null) {
                return super.loadClass(name, resolve);
            }
            InputStream is = null;
            try {
                is = super.getResourceAsStream(name.replace('.', '/') + ".class");
                if (is == null) {
                    throw new ClassNotFoundException(name);
                }
                ClassReader reader = new ClassReader(is);
                ClassWriter writer = new ClassWriter(0);
                tr.setTargetVisitor(writer);
                reader.accept(tr, 0);
                byte[] bytecode = writer.toByteArray();
                c = super.defineClass(null, bytecode, 0, bytecode.length);
            } catch (IOException e) {
                throw new ClassNotFoundException(name, e);
            } finally {
                if (is != null)
                    try {
                        is.close();
                    } catch (Throwable ignore) {}
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }

    public void addTransformer(String className, ClassTransformer transformer) {
        if (className == null || className.length() == 0)
            throw new IllegalArgumentException("className");
        if (transformer == null)
            throw new IllegalArgumentException("transformer");
        this.transformers.put(className, transformer);
    }
}

Код

package com.test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.EmptyVisitor;

public class AddFieldAnnoClassTransformer extends ClassAdapter implements ClassTransformer {

    private Map<String, Annotation> fieldsTargets;

    public AddFieldAnnoClassTransformer() {
        super(new EmptyVisitor());
        this.fieldsTargets = new HashMap<String, Annotation>();
    }

    @Override
    public void setTargetVisitor(ClassVisitor cv) {
        super.cv = cv;
    }

    public void addTargetField(String fieldName, Annotation annotation) {
        if (fieldName == null || fieldName.length() == 0)
            throw new IllegalArgumentException("fieldName");
        if (annotation == null)
            throw new IllegalArgumentException("annotation");
        this.fieldsTargets.put(fieldName, annotation);
    }

    @Override
    public FieldVisitor visitField(int access, String name, String desc,
            String signature, Object value) {
        final FieldVisitor fv = super.visitField(access, name, desc, signature,
                value);
        if (!this.fieldsTargets.containsKey(name)) {
            return fv;
        }
        final Annotation annotation = this.fieldsTargets.get(name);
        final String annoDesc = Type.getDescriptor(annotation.annotationType());
        return new FieldVisitor() {

            boolean alreadyAnnotated = false;

            @Override
            public AnnotationVisitor visitAnnotation(String desc,
                    boolean visible) {
                this.alreadyAnnotated |= desc.equals(annoDesc);
                return fv.visitAnnotation(desc, visible);
            }

            @Override
            public void visitAttribute(Attribute attr) {
                fv.visitAttribute(attr);
            }

            @Override
            public void visitEnd() {
                if (!this.alreadyAnnotated) {
                    this.copyAnnotation(fv.visitAnnotation(annoDesc, true),    annotation);
                }
                fv.visitEnd();
            }

            private void copyAnnotation(AnnotationVisitor av, Annotation anno) {
                Method[] methods = anno.annotationType().getDeclaredMethods();
                for (Method m : methods) {
                    try {
                        Object defaultValue = m.getDefaultValue();
                        Object o = m.invoke(anno, (Object[]) null);
                        if (defaultValue != null && defaultValue == o)
                            continue;
                        this.visitValue(av, m.getName(), o);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
                av.visitEnd();
            }

            private void copyArray(AnnotationVisitor av, Object array) {
                for (int i = 0, len = Array.getLength(array); i < len; ++i) {
                    Object o = Array.get(array, i);
                    this.visitValue(av, null, o);
                }
                av.visitEnd();
            }
            
            private void visitValue(AnnotationVisitor av, String name, Object value) {
                if (value instanceof Class<?>) {
                    av.visit(name, Type.getType((Class<?>) value));
                } else if (value instanceof Enum<?>) {
                    Enum<?> e = (Enum<?>) value;
                    av.visitEnum(name, Type.getDescriptor(e.getDeclaringClass()), e.name());
                } else if (value instanceof Annotation) {
                    Annotation a = (Annotation) value;
                    copyAnnotation(av.visitAnnotation(name, Type.getDescriptor(a.annotationType())), a);
                } else if (value.getClass().isArray() &&
                        !value.getClass().getComponentType().isPrimitive()) {
                    copyArray(av.visitArray(name), value);
                } else {
                    av.visit(name, value);
                }
            }
        };
    }
}

Как то так.
PM MAIL   Вверх
Foror
Дата 12.5.2009, 06:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 14.2.2004

Репутация: 1
Всего: 2



Ага, спасибо, попробую этот код на неделе. Я же решил сделать просто через генерацию XML override в hibernate annotations, где в target указывать нужный класс.
--------------------
Разработка веб-сайтов и создание интернет магазина
PM MAIL WWW ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java EE (J2EE) и Spring | Следующая тема »


 




[ Время генерации скрипта: 0.0630 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.