Beispiel zur Dependency Injection in Eclipse RCP View mit AspectJ und Spring

Thomas Darimont

Erfahrenes Mitglied
Hallo,

hier mal ein kleines Beispiel wie man mit AspectJ / Annotations und Spring nachträglich in Eclipse Komponenten (View, Editoren, etc...) injezieren kann. Dies kann man auf zwei Arten implementieren. Einmal mit statischem Compile-Time weaving
(dazu machen wir das Plugin Projekt zu einem Aspectj Project) oder per Load-Time-Weaving über einen entsprechenden
Java Agenten der über das Instrumentation API den bytecode der Klassen beim Laden modifiziert.

Hier werde ich zunächst einmal den Statischen Weg zeigen und später dann den dynamischen Weg nachreichen.

Als Beispiel nehmen wir hier einfach die Mail template Anwendung. Dort wollen wir einen BusinessService injezieren.
Wir legen also mit dem Plugin-Wizzard eine Mail Template Anwendung an (New-> Plugin Project-> RCP Application -> Mail Template) Anschließend sagen wir AspectJ Tools -> convert to AspectJ Project.

Unser Business Service Interface
Java:
/**
 * 
 */
package de.tutorials.rcp.withspringandaspectj.services;

/**
 * @author Thomas.Darimont
 *
 */
public interface IBusinessService {
    String businessOperation(String argument);
}

Unsere Implementierung:
Java:
/**
 * 
 */
package de.tutorials.rcp.withspringandaspectj.services.internal;

import de.tutorials.rcp.withspringandaspectj.services.IBusinessService;

/**
 * @author Thomas.Darimont
 * 
 */
public class BusinessService implements IBusinessService {
    public String businessOperation(String argument) {
        return "Upper: " + argument.toUpperCase();
    }
}

So nun statten wir unsere Mail Beispielanwendung erstmal mit den notwendigen Bilbiotheken aus.
Wir brauchen das spring.jar , spring-aspects.jar (findet man im dist Verzeichnis der Springframework Distribution)
und commons-logging.jar (lib/jakrata-commons), cg-lib-nodepend2.1_3.jar (lib/cglib), dom4j-xxx.jar (lib/dom4j).

Das Springframework findet man hier (die -with-dependencies) Variante enthält alle notwendigen Bibliotheken auf einen Schlag.
http://www.springframework.org/download

Diese Bibliotheken legen wir in den Runtime-Classpath unserer Anwendung:
Manfest-Editor -> Runtime -> Classpath (hier die jars hinzufügen)

Nun modifizieren wir die generierte NavigationView Klasse:
Java:
package de.tutorials.rcp.withspringandaspectj;

import java.util.ArrayList;

import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.springframework.beans.factory.annotation.Configurable;

import de.tutorials.rcp.withspringandaspectj.services.IBusinessService;

@Configurable
public class NavigationView extends ViewPart {
    public static final String ID = "de.tutorials.rcp.withSpringAndAspectJ.navigationView";
    private TreeViewer viewer;
    
    IBusinessService businessService;
     
    class TreeObject {
        private String name;
        private TreeParent parent;
        
        public TreeObject(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
        public void setParent(TreeParent parent) {
            this.parent = parent;
        }
        public TreeParent getParent() {
            return parent;
        }
        public String toString() {
            return getName();
        }
    }
    
    class TreeParent extends TreeObject {
        private ArrayList children;
        public TreeParent(String name) {
            super(name);
            children = new ArrayList();
        }
        public void addChild(TreeObject child) {
            children.add(child);
            child.setParent(this);
        }
        public void removeChild(TreeObject child) {
            children.remove(child);
            child.setParent(null);
        }
        public TreeObject[] getChildren() {
            return (TreeObject[]) children.toArray(new TreeObject[children.size()]);
        }
        public boolean hasChildren() {
            return children.size()>0;
        }
    }

    class ViewContentProvider implements IStructuredContentProvider, 
                                           ITreeContentProvider {

        public void inputChanged(Viewer v, Object oldInput, Object newInput) {
        }
        
        public void dispose() {
        }
        
        public Object[] getElements(Object parent) {
            return getChildren(parent);
        }
        
        public Object getParent(Object child) {
            if (child instanceof TreeObject) {
                return ((TreeObject)child).getParent();
            }
            return null;
        }
        
        public Object[] getChildren(Object parent) {
            if (parent instanceof TreeParent) {
                return ((TreeParent)parent).getChildren();
            }
            return new Object[0];
        }

        public boolean hasChildren(Object parent) {
            if (parent instanceof TreeParent)
                return ((TreeParent)parent).hasChildren();
            return false;
        }
    }
    
    class ViewLabelProvider extends LabelProvider {

        public String getText(Object obj) {
            return obj.toString();
        }
        public Image getImage(Object obj) {
            String imageKey = ISharedImages.IMG_OBJ_ELEMENT;
            if (obj instanceof TreeParent)
               imageKey = ISharedImages.IMG_OBJ_FOLDER;
            return PlatformUI.getWorkbench().getSharedImages().getImage(imageKey);
        }
    }

    /**
     * We will set up a dummy model to initialize tree heararchy. In real
     * code, you will connect to a real model and expose its hierarchy.
     */
    private TreeObject createDummyModel() {
        TreeObject to1 = new TreeObject("Inbox");
        TreeObject to2 = new TreeObject("Drafts");
        TreeObject to3 = new TreeObject("Sent");
        TreeParent p1 = new TreeParent("me@this.com");
        p1.addChild(to1);
        p1.addChild(to2);
        p1.addChild(to3);

        TreeObject to4 = new TreeObject("Inbox");
        TreeParent p2 = new TreeParent("other@aol.com");
        p2.addChild(to4);

        TreeParent root = new TreeParent("");
        root.addChild(p1);
        root.addChild(p2);
        return root;
    }

    /**
     * This is a callback that will allow us to create the viewer and initialize
     * it.
     */
    public void createPartControl(Composite parent) {
        viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
        viewer.setContentProvider(new ViewContentProvider());
        viewer.setLabelProvider(new ViewLabelProvider());
        viewer.setInput(createDummyModel());
    }

    /**
     * Passing the focus request to the viewer's control.
     */
    public void setFocus() {
        viewer.getControl().setFocus();
    }

    public IBusinessService getBusinessService() {
        return businessService;
    }

    public void setBusinessService(IBusinessService businessService) {
        System.out.println("Set businessService: " + businessService);
        this.businessService = businessService;
    }
    
    @Override
    public void init(IViewSite site) throws PartInitException {
        System.out.println("init -> viewSite: " + site);
        System.out.println("init -> businessService: " + getBusinessService());
        super.init(site);
    }
    

}
Hier annotieren wir die Klasse mit @Configurable
und überschreiben die init(...) Methode von ViewPart diese wird von der Eclipse Platform nach dem erzeugen einer View aufgerufen um ihren Lebenszyklus zu starten. Weiterhin haben wir den Business Service als Attribut aufgehängt und entsprechende getter/setter generiert.

Unsere Spring-Konfiguration schaut nun so aus:
applicationContext.xml:
XML:
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:aop="http://www.springframework.org/schema/aop"
         xmlns:tx="http://www.springframework.org/schema/tx"
         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

    <bean name="NavigationView" class="de.tutorials.rcp.withspringandaspectj.NavigationView" lazy-init="true">
        <property name="businessService" ref="businessService"/>
    </bean>
    
    <bean name="businessService" class="de.tutorials.rcp.withspringandaspectj.services.internal.BusinessService"/>
</beans>

Unser Activator startet den Springframework-Kontext beim Start unserer Anwendung:
Java:
package de.tutorials.rcp.withspringandaspectj;

import org.eclipse.core.runtime.FileLocator;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * The activator class controls the plug-in life cycle
 */
public class Activator extends AbstractUIPlugin {

    // The plug-in ID
    public static final String PLUGIN_ID = "de.tutorials.rcp.withSpringAndAspectJ";

    // The shared instance
    private static Activator plugin;

    private ApplicationContext applicationContext;

    /**
     * The constructor
     */
    public Activator() {
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
     */
    public void start(BundleContext context) throws Exception {
        super.start(context);
        plugin = this;
        this.applicationContext = createApplicationContext();
    }

    /**
     * 
     */
    private ApplicationContext createApplicationContext() {
        Thread.currentThread().setContextClassLoader(
                Activator.class.getClassLoader());

        try {
            return new ClassPathXmlApplicationContext(FileLocator.toFileURL(
                    getBundle().getResource("config/applicationContext.xml"))
                    .toString());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
     */
    public void stop(BundleContext context) throws Exception {
        plugin = null;
        super.stop(context);
    }

    /**
     * Returns the shared instance
     * 
     * @return the shared instance
     */
    public static Activator getDefault() {
        return plugin;
    }

    /**
     * Returns an image descriptor for the image file at the given plug-in
     * relative path
     * 
     * @param path
     *            the path
     * @return the image descriptor
     */
    public static ImageDescriptor getImageDescriptor(String path) {
        return imageDescriptorFromPlugin(PLUGIN_ID, path);
    }

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

}

Nun kommen unsere Aspekte:
Unser abstracter Configuration aspect bietet die Möglichkeit Objete nach ihrer Erzeugung mit new durch den
abstracten objectInitialization pointcut nachträglich mit Spring zu konfigurieren:
Java:
/**
 * 
 */
package de.tutorials.rcp.withspringandaspectj.aspects;

import de.tutorials.rcp.withspringandaspectj.Activator;
import org.springframework.beans.factory.annotation.Configurable;

/**
 * @author Thomas.Darimont
 * 
 */
public abstract aspect Configuration {
    
    public abstract pointcut objectInitialization(Object instance);
    
    public pointcut configurableAnnotationIsPresent():
        within(@Configurable *);
    
    before(Object instance) : objectInitialization(instance) && configurableAnnotationIsPresent(){
        System.out.println("Configuring " + instance.getClass());
        Activator.getDefault().getApplicationContext()
                .getAutowireCapableBeanFactory().configureBean(instance,
                        instance.getClass().getSimpleName());
    }
}
Das funktioniert fast genau so wie ich's schonmal für googles Guice gezeigt hatte:
http://www.tutorials.de/forum/java/...e-bei-mit-new-erzeugten-beans-mt-aspectj.html

Für die Konfiguration einer View sieht ein konkreter Aspect dazu dann ungefähr so aus:
Java:
/**
 * 
 */
package de.tutorials.rcp.withspringandaspectj.aspects;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.IViewSite;


/**
 * @author Thomas.Darimont
 *
 */
public aspect ViewConfiguration extends Configuration{
    public pointcut objectInitialization(Object instance):
        execution(* ViewPart+.init(IViewSite) ) && this(instance);

}

Damit wären wir auch schon fertig.
Zum Starten klicken wir mit der Maus auf das Projekt mit der rechten Maustaste und wählen im Kontextmenü,
run -> as eclipse application aus. Sollte das nicht klappen muss man die Launch-Configuration anpassen.
Dazu geht man einfach in der Launch-Configuration auf den Reiter Plugins, deselektiert erstmal alles, klickt dann
nur "unser" Plugin-Projekt im Workspace an und sagt -> Add required Plugins. Anschließend klickt man auf apply und schon sollte es gehen.
Ausgabe bei mir :
Code:
24.06.2007 17:25:08 org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1b1fbf4: display name [org.springframework.context.support.ClassPathXmlApplicationContext@1b1fbf4]; startup date [Sun Jun 24 17:25:08 CEST 2007]; root of context hierarchy
24.06.2007 17:25:08 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from URL [file:/C:/Dokumente und Einstellungen/Thomas.Darimont/workspace-3.3RC4/de.tutorials.rcp.withSpringAndAspectJ/config/applicationContext.xml]
24.06.2007 17:25:08 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
INFO: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@1b1fbf4]: org.springframework.beans.factory.support.DefaultListableBeanFactory@b3319f
24.06.2007 17:25:08 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@b3319f: defining beans [NavigationView,businessService]; root of factory hierarchy
Configuring class de.tutorials.rcp.withspringandaspectj.NavigationView
Set businessService: de.tutorials.rcp.withspringandaspectj.services.internal.BusinessService@771eb1
init -> viewSite: PartSite(id=de.tutorials.rcp.withSpringAndAspectJ.navigationView,pluginId=de.tutorials.rcp.withSpringAndAspectJ,registeredName=Mailboxes,hashCode=8392793)
init -> businessService: de.tutorials.rcp.withspringandaspectj.services.internal.BusinessService@771eb1

Das Projekt (ohne Libraries) findet man im Anhang.

Gruß Tom
 

Anhänge

  • projectLayoutSpringAspectJEclispeRCP.jpg
    projectLayoutSpringAspectJEclispeRCP.jpg
    71,1 KB · Aufrufe: 874
  • de.tutorials.rcp.withSpringAndAspectJ.zip
    123,8 KB · Aufrufe: 202
Zuletzt bearbeitet von einem Moderator:
Hallo,

hier dann mal das Beispiel das mit Load-time weaving funktioniert ohne eigene Aspekte.
Wie man mit load-time weaving arbeitet hab ich vorher schon mal hier gezeigt:
http://www.tutorials.de/forum/1239971-post1.html

Für dieses Beispiel gehen wir wieder vom obigen Projekt aus. Als erstes entfernen wir die AspectJ-Project Nature, so dass der AJDT Compiler nicht mehr aktiv wird.

Anschließend fügen wir unserem Projekt ein paar neue Bibliotheken hinzu:
1) aspectjrt.jar und aspectjweaver.jar (findet man Beispielsweise unter:
D:\stuff\springframework\2.1M1\spring-framework-2.1-m1\lib\aspectj )
2) spring-agent.jar (findet man unter D:\stuff\springframework\2.1M1\spring-framework-2.1-m1\dist\weavers)

Diese kopieren wir in unser Lib-Verzeichnis und fügen diese im Runtime-Tab unserer Bundle-Konfiguration zum Classpath hinzu.

Nun müssen wir noch unsere Spring Konfiguration anpassen:
XML:
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	     xmlns:aop="http://www.springframework.org/schema/aop"
	     xmlns:tx="http://www.springframework.org/schema/tx"
	     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

	<aop:spring-configured/>
	
	<!--  name="NavigationView"  -->
	<bean class="de.tutorials.rcp.withspringandaspectj.NavigationView" lazy-init="true">
		<property name="businessService" ref="businessService"/>
	</bean>
	
	<bean name="businessService" class="de.tutorials.rcp.withspringandaspectj.services.internal.BusinessService"/>
</beans>

Anschließend erzeugen wir im META-INF Verzeichnis eine Datei namens aop.xml:
XML:
<!DOCTYPE aspectj PUBLIC    
  "-//AspectJ//DTD//EN"    "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">    

<aspectj>    
   <weaver 
     options="-showWeaveInfo -verbose">
     <include within="org.eclipse.ui.part.ViewPart+"/>
   </weaver>
</aspectj>
Damit teilen wir dem AspetJWeaver mit das alle von ViewPart abgeleiteten Typen mit dem entsprechendem Spring-Aspect geweaved werden sollen (natürlich werden nur die geweaved die auch mit dem beanCreation Pointcut matchen -> D:\stuff\springframework\2.1M1\spring-framework-2.1-m1\aspectj\src\org\springframework\beans\factory\aspectj )

Die Anwendung starten wir nun mit der JVM Option:
Code:
-javaagent:D:\projects\eclipse\spring-aop\de.tutorials.rcp.withSpringAndAspectJ\lib\aspectjweaver.jar

Ausgabe:
Code:
[DefaultClassLoader@12c8fa8] info AspectJ Weaver Version 1.5.3 built on Wednesday Nov 22, 2006 at 11:18:15 GMT
[DefaultClassLoader@12c8fa8] info register classloader org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader@12c8fa8
[DefaultClassLoader@12c8fa8] info using configuration /META-INF/aop.xml
[DefaultClassLoader@12c8fa8] info using configuration /META-INF/aop.xml
[DefaultClassLoader@12c8fa8] info register aspect org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect
[DefaultClassLoader@12c8fa8] info register aspect org.springframework.transaction.aspectj.AnnotationTransactionAspect
30.06.2007 13:53:03 org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@9260ee: display name [org.springframework.context.support.ClassPathXmlApplicationContext@9260ee]; startup date [Sat Jun 30 13:53:03 CEST 2007]; root of context hierarchy
30.06.2007 13:53:03 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from URL [file:/D:/projects/eclipse/spring-aop/de.tutorials.rcp.withSpringAndAspectJ/config/applicationContext.xml]
30.06.2007 13:53:03 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
INFO: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@9260ee]: org.springframework.beans.factory.support.DefaultListableBeanFactory@64160e
[DefaultClassLoader@12c8fa8] weaveinfo Join point 'initialization(void de.tutorials.rcp.withspringandaspectj.NavigationView.<init>())' in Type 'de.tutorials.rcp.withspringandaspectj.NavigationView' (NavigationView.java:23) advised by afterReturning advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect' (AbstractBeanConfigurerAspect.aj:43) [with runtime test]
30.06.2007 13:53:03 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@64160e: defining beans [org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect,de.tutorials.rcp.withspringandaspectj.NavigationView,businessService]; root of factory hierarchy
Set businessService: de.tutorials.rcp.withspringandaspectj.services.internal.BusinessService@db248c
init -> viewSite: PartSite(id=de.tutorials.rcp.withSpringAndAspectJ.navigationView,pluginId=de.tutorials.rcp.withSpringAndAspectJ,registeredName=Mailboxes,hashCode=3870732)
init -> businessService: de.tutorials.rcp.withspringandaspectj.services.internal.BusinessService@db248c

Gruß Tom
 

Anhänge

  • de.tutorials.rcp.withSpringAndAspectJ2.zip
    120,1 KB · Aufrufe: 91
Zuletzt bearbeitet von einem Moderator:
Hallo,

wer ganz ohne eigene Aspekte auskommen möchte kann natürlich auch in den Project Properties (bei einem AspectJ Project) über AspectJ Build -> Aspect Path -> das Spring-aspects.jar angeben. Dann gehts auch ohne eigene Aspects.

Gruß Tom
 
hallo, erstmal ein Lob für die super artikel hier bei tutorials.de. jetzt zu meiner frage:

Ein New Wizard wird ja per new erzeugt, wenn ich im NewWizardDialog den Wizard verwende. Ich möchte dem so erzeugten Wizard ein Property bei seiner Erzeugung mitgeben. Eberhard Wolff verwendet in seinem Buch den AnnotationBeanConfigurerAspect um mit Configurable annotierte Klassen (in meinem Fall der besagt NewWizard) mit Spring zu konfigurieren. Bei wird der Wizard wohl nicht nachträglich konfiguriert. da das property null bleibt.

jemand vielleicht ne idee?

gruß René Gröschke

meine beans.xml:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
 
	<aop:spring-configured/>
	<bean class="...wizards.NewCommandWizard">
		<property name="commandDao" ref="serverFacade"/>
	</bean>
	
	<bean name="serverFacade" class="....ServerFacade">
		<property name="service" ref="commandService" />
	</bean>

	<bean id="commandService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
		<property name="serviceUrl"
			value="http://localhost:9090/remote/CommandService" />
		<property name="serviceInterface" value="....CommandService" />
	</bean>
	
	
	<bean class="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect" factory-method="aspectOf"/>

</beans>
 
Hallo,

ich hab das obige Beispiel mal um einen Wizard erweitert und benutze nun nur noch die Standard Aspects aus dem Spring-Aspects.jar. (Project Properties -> AspectJ Build -> Aspect Path -> spring-aspects.jar)


Mein einfacher Wizard:
Java:
/**
 * 
 */
package de.tutorials.rcp.withspringandaspectj.wizards;

import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.springframework.beans.factory.annotation.Configurable;

import de.tutorials.rcp.withspringandaspectj.services.IBusinessService;

/**
 * @author Thomas.Darimont
 * 
 */
@Configurable
public class NewMessageWizard extends Wizard implements INewWizard {

    static{
        System.out.println("xxxxxxx");
    }
    
    IBusinessService businessService;

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.jface.wizard.Wizard#performFinish()
     */
    @Override
    public boolean performFinish() {
        // TODO Auto-generated method stub
        return true;
    }

    public IBusinessService getBusinessService() {
        return businessService;
    }

    public void setBusinessService(IBusinessService businessService) {
        System.out.println("Set businessService: " + businessService);
        this.businessService = businessService;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.IWorkbenchWizard#init(org.eclipse.ui.IWorkbench,
     *      org.eclipse.jface.viewers.IStructuredSelection)
     */
    public void init(IWorkbench workbench, IStructuredSelection selection) {

        System.out.println(this + ": init -> workbench: " + workbench);
        System.out.println(this + ": init -> businessService: "
                + getBusinessService());
    }

}

applicationContext.xml:
XML:
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:aop="http://www.springframework.org/schema/aop"
         xmlns:tx="http://www.springframework.org/schema/tx"
         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

    <aop:spring-configured/>
    
    <bean class="de.tutorials.rcp.withspringandaspectj.NavigationView" lazy-init="true">
        <property name="businessService" ref="businessService"/>
    </bean>
    
    <bean class="de.tutorials.rcp.withspringandaspectj.wizards.NewMessageWizard" lazy-init="true">
        <property name="businessService" ref="businessService"/>
    </bean>
        
    <bean name="businessService" class="de.tutorials.rcp.withspringandaspectj.services.internal.BusinessService"/>
</beans>


Ausgabe nach einem Klick auf new-> NewMessageWizard:
Code:
02.08.2007 23:33:48 org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@ff057f: display name [org.springframework.context.support.ClassPathXmlApplicationContext@ff057f]; startup date [Thu Aug 02 23:33:48 CEST 2007]; root of context hierarchy
02.08.2007 23:33:48 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from URL [file:/C:/Dokumente und Einstellungen/Thomas.Darimont/workspace-europa/de.tutorials.rcp.withSpringAndAspectJ/config/applicationContext.xml]
02.08.2007 23:33:48 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
INFO: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@ff057f]: org.springframework.beans.factory.support.DefaultListableBeanFactory@1bcdbf6
02.08.2007 23:33:48 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1bcdbf6: defining beans [org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect,de.tutorials.rcp.withspringandaspectj.NavigationView,de.tutorials.rcp.withspringandaspectj.wizards.NewMessageWizard,businessService]; root of factory hierarchy
Set businessService: de.tutorials.rcp.withspringandaspectj.services.internal.BusinessService@813bc1
de.tutorials.rcp.withspringandaspectj.NavigationView@57807a: init -> viewSite: PartSite(id=de.tutorials.rcp.withSpringAndAspectJ.navigationView,pluginId=de.tutorials.rcp.withSpringAndAspectJ,registeredName=Mailboxes,hashCode=11782857)
de.tutorials.rcp.withspringandaspectj.NavigationView@57807a: init -> businessService: de.tutorials.rcp.withspringandaspectj.services.internal.BusinessService@813bc1
xxxxxxx
Set businessService: de.tutorials.rcp.withspringandaspectj.services.internal.BusinessService@813bc1
de.tutorials.rcp.withspringandaspectj.wizards.NewMessageWizard@8698fa: init -> workbench: org.eclipse.ui.internal.Workbench@a56214
de.tutorials.rcp.withspringandaspectj.wizards.NewMessageWizard@8698fa: init -> businessService: de.tutorials.rcp.withspringandaspectj.services.internal.BusinessService@813bc1

Gruß Tom
 

Anhänge

  • de.tutorials.rcp.withSpringAndAspectJWithWizard.zip
    123,2 KB · Aufrufe: 68
  • aspectJEclipseSpring.jpg
    aspectJEclipseSpring.jpg
    36,4 KB · Aufrufe: 283
Zuletzt bearbeitet von einem Moderator:
Soweit so gut

dem beispiel konnt ich folgen.

ich benutze in meiner EclipseRCP third party librarys verpackt in einem eigenen Plugin (create plugin from exisiting jars). also möchte ich die libs aus dem lib ordner in ein eigens plugin packen. jetzte habe ich die folgenden librarys aus dem lib order meines plugins (dass spring verwendet in ein eigenes plugin (org.springframework.spring) gepackt:

- aspectjrt.jar
- aspectjweaver.jar
- cglib-nodep-2.1_3.jar
- dom4j-1.6.1.jar
- spring.jar
- spring-agent.jar
- spring-aspects.jar

nachdem ich die oben genannten jars in ein extra plugin verpackt habe und statt im classpath des plugins auf die jars zu verweisen, jetzt auf das plugin verweise werden die aspekte nicht ausgeführt.

in beiden konfigurationen erhalte ich beim laden des plugins folgende fehlermeldung, wobei es trotz fehlermeldung in der konfiguration mit dem lib ordner funktioniert:

Code:
[DefaultClassLoader@1f1f38e] error Cannot instantiate message handler org.springframework.aop.aspectj.AspectJWeaverMessageHandler -- (ClassCastException) org.springframework.aop.aspectj.AspectJWeaverMessageHandler
org.springframework.aop.aspectj.AspectJWeaverMessageHandler
java.lang.ClassCastException: org.springframework.aop.aspectj.AspectJWeaverMessageHandler
	at org.aspectj.weaver.loadtime.Options.parse(Options.java:69)
	at org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor.registerOptions(ClassLoaderWeavingAdaptor.java:272)
	at org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor.registerDefinitions(ClassLoaderWeavingAdaptor.java:237)
	at org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor.initialize(ClassLoaderWeavingAdaptor.java:152)
	at org.aspectj.weaver.loadtime.Aj$ExplicitlyInitializedClassLoaderWeavingAdaptor.initialize(Aj.java:151)
	at org.aspectj.weaver.loadtime.Aj$ExplicitlyInitializedClassLoaderWeavingAdaptor.getWeavingAdaptor(Aj.java:156)
	at org.aspectj.weaver.loadtime.Aj$WeaverContainer.getWeaver(Aj.java:122)
	at org.aspectj.weaver.loadtime.Aj.preProcess(Aj.java:73)
	at org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:55)
	at sun.instrument.TransformerManager.transform(Unknown Source)
	at sun.instrument.InstrumentationImpl.transform(Unknown Source)
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(Unknown Source)
	at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.defineClass(DefaultClassLoader.java:161)
	at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.defineClass(ClasspathManager.java:501)
	at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findClassImpl(ClasspathManager.java:471)
	at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findLocalClassImpl(ClasspathManager.java:430)
	at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findLocalClass(ClasspathManager.java:413)
	at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.findLocalClass(DefaultClassLoader.java:189)
	at org.eclipse.osgi.framework.internal.core.BundleLoader.findLocalClass(BundleLoader.java:340)
	at org.eclipse.osgi.framework.internal.core.BundleLoader.findClassInternal(BundleLoader.java:408)
	at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:369)
	at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:357)
	at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:83)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at org.eclipse.osgi.framework.internal.core.BundleLoader.loadClass(BundleLoader.java:289)
	at org.eclipse.osgi.framework.internal.core.BundleHost.loadClass(BundleHost.java:227)
	at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadClass(AbstractBundle.java:1269)
	at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.createExecutableExtension(RegistryStrategyOSGI.java:160)
	at org.eclipse.core.internal.registry.ExtensionRegistry.createExecutableExtension(ExtensionRegistry.java:788)
	at org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(ConfigurationElement.java:243)
	at org.eclipse.core.internal.registry.ConfigurationElementHandle.createExecutableExtension(ConfigurationElementHandle.java:51)
	at org.eclipse.ui.internal.registry.PerspectiveDescriptor.createFactory(PerspectiveDescriptor.java:172)
	at org.eclipse.ui.internal.Perspective.loadPredefinedPersp(Perspective.java:696)
	at org.eclipse.ui.internal.Perspective.createPresentation(Perspective.java:258)
	at org.eclipse.ui.internal.Perspective.<init>(Perspective.java:146)
	at org.eclipse.ui.internal.WorkbenchPage.createPerspective(WorkbenchPage.java:1537)
	at org.eclipse.ui.internal.WorkbenchPage.busySetPerspective(WorkbenchPage.java:981)
	at org.eclipse.ui.internal.WorkbenchPage.access$17(WorkbenchPage.java:972)
	at org.eclipse.ui.internal.WorkbenchPage$18.run(WorkbenchPage.java:3560)
	at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:67)
	at org.eclipse.ui.internal.WorkbenchPage.setPerspective(WorkbenchPage.java:3558)
	at org.eclipse.ui.internal.ChangeToPerspectiveMenu.run(ChangeToPerspectiveMenu.java:92)
	at org.eclipse.ui.actions.PerspectiveMenu.run(PerspectiveMenu.java:336)
	at org.eclipse.ui.actions.PerspectiveMenu.runOther(PerspectiveMenu.java:352)
	at org.eclipse.ui.actions.PerspectiveMenu$3.runWithEvent(PerspectiveMenu.java:108)
	at org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection(ActionContributionItem.java:545)
	at org.eclipse.jface.action.ActionContributionItem.access$2(ActionContributionItem.java:490)
	at org.eclipse.jface.action.ActionContributionItem$5.handleEvent(ActionContributionItem.java:402)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:66)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:938)
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3682)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3293)
	at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2389)
	at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2353)
	at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2219)
	at org.eclipse.ui.internal.Workbench$4.run(Workbench.java:466)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:289)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:461)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
	at com.eads.guppy.base.Application.start(Application.java:21)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:153)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:106)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:76)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:363)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:176)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:504)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:443)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1169)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1144)

bin mir nicht sicher woran das liegen kann. beim einbinden von librarys als eigene plugins machen bibliotheken probleme die class.forName verwenden. das wirds wohl sein. bleibt halt noch das problem mit der ClassCastException beim initialsieren des plugins
 
Zuletzt bearbeitet:
Hallo,

ich würd' hier drauf tippen, dass eine Klasse von unterschiedlichen ClassLoadern geladen wurde... dann hast du zwei Repräsentationen der selben Class-Instanz... wenn du nun eine Instanz der Klasse, welche durch ClassLoaderA geladen worden ist, versuchst auf eine Klasse die von ClassLoaderB geladen worden ist zu casten gibts ne ClassCastException.

Gruß Tom
 
Sorry der Thread ist schon etwas älter aber für mich hoch aktuell ;)

Gibt es jetzt eigentlich eine Lösung für das ClassLoader Problem, wenn man Spring in ein zusätzliches Plugin auslagert?
Habe schon einiges mit der Buddy-Funktion von eclipse rumprobiert, aber bei mir steigt er auch schon früher aus, da er die xsd für den neuen (seit 2.5) "context" namespace nicht findet (<context:spring-configured />). Nur die ersten beiden Traces bis zum Laden der app-context xml werden noch angezeigt, also grundsätzlich kann er auf die Spring Klassen zugreifen. Eigentlich ist das Buddy-Konzept ja auch nur dafür da, damit das spring plugin dann auf mein eigenes plugin zugreifen kann ohne eine direkte plugin abhängigkeit zu besitzen...

Sind denn zwei plugins automatisch immer zwei verschiedene ClassLoader, egal was man einstellt?

Aber sobald die libs nicht mehr ausgelagert sind funktioniert alles wie auch oben beschrieben.
 
Hallo,

Gibt es jetzt eigentlich eine Lösung für das ClassLoader Problem, wenn man Spring in ein zusätzliches Plugin auslagert?
Das ist kein Problem sondern alles nur eine Sache von der richtigen Konfiguration der Plugin Abhängigkeiten und Buddy-Classloading.

schau mal hier:
http://www.tutorials.de/forum/java/303535-spring-dynamic-modules-osgi-und-aspectj.html
http://www.tutorials.de/forum/java/...clipse-extensionpoints.html?highlight=equinox
http://www.tutorials.de/forum/java/...ebare-db-funktionaliaet-fuer-eclipse-rcp.html

Sind denn zwei plugins automatisch immer zwei verschiedene ClassLoader, egal was man einstellt?
Ja, jedes Bundle hat seinen eigenen ClassLoader. Was du beeinflussen kannst ist die Art und Weise wie die ClassLoader verwendet werden.

Gruß Tom
 

Neue Beiträge

Zurück