changeset 11:7f267a1c3d63

7902119: Add JemmySupport to jemmy/v3 Reviewed-by: ogb
author shurailine
date Tue, 08 Jan 2019 15:44:49 -0800
parents 72b4d8016653
children c1848648774f
files core/JemmySupport/build.xml core/JemmySupport/src/org/jemmy/support/ControlInterfaceSupport.java core/JemmySupport/src/org/jemmy/support/ControlSupport.java core/JemmySupport/src/org/jemmy/support/DefaultParentSupport.java core/JemmySupport/src/org/jemmy/support/DefaultWrapperSupport.java core/JemmySupport/src/org/jemmy/support/DirectPropertySupport.java core/JemmySupport/src/org/jemmy/support/DockGenerator.java core/JemmySupport/src/org/jemmy/support/DumpGenerator.java core/JemmySupport/src/org/jemmy/support/LookupSupport.java core/JemmySupport/src/org/jemmy/support/MappedPropertySupport.java core/JemmySupport/src/org/jemmy/support/Processor.java core/JemmySupport/src/org/jemmy/support/SupportParameter.java core/JemmySupport/src/org/jemmy/support/Version.java core/JemmySupport/src/org/jemmy/support/jemmy.properties core/JemmySupport/src/org/jemmy/support/package.html.html core/JemmySupport/test/org/jemmy/support/DockTest.java core/JemmySupport/test_data/com/company/test/CollectionRoot.java core/JemmySupport/test_data/com/company/test/CollectionWrap.java core/JemmySupport/test_data/com/company/test/ListWrap.java core/JemmySupport/test_data/com/company/test/ObjectWrap.java core/make/jemmy-v3-ii/.idea/misc.xml core/make/jemmy-v3-ii/.idea/modules.xml make/build_template.xml
diffstat 23 files changed, 2867 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/build.xml	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ This code is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License version 2 only, as
+ published by the Free Software Foundation.
+
+ This code is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ version 2 for more details (a copy is included in the LICENSE file that
+ accompanied this code).
+
+ You should have received a copy of the GNU General Public License version
+ 2 along with this work; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ or visit www.oracle.com if you need additional information or have any
+ questions.
+ -->
+<project name="jemmy-support" default="compile" basedir=".">
+    <import file="${basedir}/../../make/build_template.xml"/>
+    <property name="core.jar" location="../JemmyCore/build/JemmyCore.jar"/>
+    <property name="version.file" value="org/jemmy/support/jemmy.properties"/>
+    <property name="version.class" value="org.jemmy.support.Version"/>
+    <property name="dependencies.classpath" value="${core.jar}"/>
+    <property name="test.data.src" location="test_data"/>
+    <property name="test.data.docks" location="${build.dir}/test_docks"/>
+    <property name="test.data.dest" location="${build.dir}/test_data"/>
+    <property name="test.dependencies.classpath" value="${test.data.dest}"/>
+    <target name="check-dependecies-impl">
+        <available file="${core.jar}" property="dependencies.are.built"/>
+    </target>
+    <target name="build-dependecies-impl">
+        <ant dir="${basedir}/../JemmyCore" target="jar" inheritAll="false"/>
+    </target>
+    <target name="build-test-dependecies-impl">
+        <delete dir="${test.data.dest}"/>
+        <mkdir dir="${test.data.dest}"/>
+        <delete dir="${test.data.docks}"/>
+        <mkdir dir="${test.data.docks}"/>
+        <javac sourcepath="" srcdir="${test.data.src}" destdir="${test.data.dest}" classpath="${core.jar}:${build.classes.dir}">
+            <compilerarg value="-processor"/>
+            <compilerarg value="org.jemmy.support.Processor"/>
+            <compilerarg value="-Aactions=docks,dump"/>
+            <compilerarg value="-s"/>
+            <compilerarg value="${test.data.docks}"/>
+        </javac>
+        <javac sourcepath="" srcdir="${test.data.docks}" destdir="${test.data.dest}" classpath="${core.jar}:${build.classes.dir}:${test.data.dest}"/>
+    </target>
+    <target name="test-dependecies-impl">
+        <ant dir="${basedir}/../JemmyCore" target="test" inheritAll="false"/>
+    </target>
+</project>
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/src/org/jemmy/support/ControlInterfaceSupport.java	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.jemmy.support;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import javax.lang.model.element.*;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import org.jemmy.dock.Shortcut;
+
+/**
+ *
+ * @author shura
+ */
+public class ControlInterfaceSupport {
+
+    public enum Kind {SELF, ANNOTATION, METHOD};
+
+    private final DeclaredType type;
+    private final DeclaredType encapsulates;
+    private final String name;
+    private final List<ShortcutSupport> shortcuts = new ArrayList<ShortcutSupport>();
+    private final Kind kind;
+    private final ExecutableElement method;
+
+    /**
+     *
+     * @param type
+     * @param encapsulates
+     * @param name
+     */
+    public ControlInterfaceSupport(Kind kind, DeclaredType type, DeclaredType encapsulates,
+            String name, ExecutableElement method,
+            List<ShortcutSupport> allShortcuts) {
+        this.kind = kind;
+        this.type = type;
+        this.encapsulates = encapsulates;
+        this.name = name;
+        this.method = method;
+        collectShortcuts(type, allShortcuts);
+    }
+
+    public Kind getKind() {
+        return kind;
+    }
+
+    public ExecutableElement getMethod() {
+        return method;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public DeclaredType getEncapsulates() {
+        return encapsulates;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public DeclaredType getType() {
+        return type;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public List<ShortcutSupport> getShortcuts() {
+        return shortcuts;
+    }
+
+    private void collectShortcuts(DeclaredType type, List<ShortcutSupport> allShortcuts) {
+        for (Element e : type.asElement().getEnclosedElements()) {
+            if (e instanceof ExecutableElement) {
+                ExecutableElement method = (ExecutableElement) e;
+                AnnotationMirror am = Processor.findAnnotation(e, Shortcut.class);
+                if (am != null) {
+                    String nm = "";
+                    AnnotationValue v = Processor.getElementValue(am, "name");
+                    if (v != null) {
+                        nm = Processor.getStringValue(v);
+                    }
+                    if (nm.length() == 0) {
+                        nm = method.getSimpleName().toString();
+                    }
+                    ShortcutSupport shortcut = new ShortcutSupport(method, nm);
+                    ControlSupport.copyParameters(method, 0, shortcut.getParams());
+                    if(!exists(shortcut, allShortcuts)) {
+                        shortcuts.add(shortcut);
+                        allShortcuts.add(shortcut);
+                    }
+                }
+            }
+        }
+        TypeElement elem = (TypeElement) type.asElement();
+        if (elem.getSuperclass() instanceof DeclaredType) {
+            collectShortcuts((DeclaredType) elem.getSuperclass(), allShortcuts);
+        }
+        for (TypeMirror intf : elem.getInterfaces()) {
+            collectShortcuts((DeclaredType) intf, allShortcuts);
+        }
+    }
+
+    private boolean exists(ShortcutSupport shortcut, List<ShortcutSupport> shortcuts) {
+        for(ShortcutSupport sc : shortcuts) {
+            if(sc.getName().equals(shortcut.getName())) {
+                if(sc.getParams().size() == shortcut.getParams().size()) {
+                    boolean same = true;
+                    for (int i = 0; i < sc.getParams().size(); i++) {
+                        if(!sc.getParams().get(i).getType().equals(shortcut.getParams().get(i).getType())) {
+                            same = false;
+                            break;
+                        }
+                    }
+                    if(same) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     *
+     */
+    public class ShortcutSupport {
+
+        private final ExecutableElement method;
+        private final String name;
+        private final List<SupportParameter> params = new LinkedList<SupportParameter>();
+        private final TypeMirror returnType;
+        private final List<DeclaredType> returnGenerics = new ArrayList<DeclaredType>();
+
+        /**
+         *
+         * @param method
+         * @param name
+         */
+        public ShortcutSupport(ExecutableElement method, String name) {
+            this.method = method;
+            this.name = name;
+            returnType = method.getReturnType();
+            if (returnType instanceof DeclaredType) {
+                for (TypeMirror g : ((DeclaredType) returnType).getTypeArguments()) {
+                    if (g.getKind() == TypeKind.TYPEVAR) {
+                        if(encapsulates != null)
+                            returnGenerics.add(encapsulates);
+                        else if(((DeclaredType) returnType).getTypeArguments().size() > 1)
+                            throw new IllegalStateException("Please specify encapsulated type for " + type.toString());
+                    } else if (g instanceof DeclaredType) {
+                        returnGenerics.add((DeclaredType) g);
+                    } else {
+                        throw new IllegalStateException("huh?");
+                    }
+                }
+            }
+        }
+
+        /**
+         *
+         * @return
+         */
+        public ExecutableElement getMethod() {
+            return method;
+        }
+
+        /**
+         *
+         * @return
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         *
+         * @return
+         */
+        public List<SupportParameter> getParams() {
+            return params;
+        }
+
+        /**
+         *
+         * @return
+         */
+        public List<DeclaredType> getReturnGenerics() {
+            return returnGenerics;
+        }
+
+        /**
+         *
+         * @return
+         */
+        public TypeMirror getReturnType() {
+            return returnType;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/src/org/jemmy/support/ControlSupport.java	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.jemmy.support;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.*;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import org.jemmy.control.*;
+import org.jemmy.dock.DefaultWrapper;
+import org.jemmy.dock.*;
+import org.jemmy.interfaces.ControlInterface;
+import org.jemmy.interfaces.Drag;
+import org.jemmy.interfaces.Keyboard;
+import org.jemmy.interfaces.Mouse;
+
+/**
+ *
+ * @author shura
+ */
+public class ControlSupport {
+
+    private final DeclaredType wrap;
+    //this could not be final 'cause an order of wraps is not defined
+    //and hence inheritance is figured out later
+    private DeclaredType superWrap = null;
+    private final DeclaredType control;
+    private final List<ControlInterfaceSupport> interfaces = new LinkedList<ControlInterfaceSupport>();
+    private final List<LookupSupport> objectLookups = new LinkedList<LookupSupport>();
+    private final List<MappedPropertySupport> properties = new LinkedList<MappedPropertySupport>();
+    private final List<DirectPropertySupport> propertyMethods = new LinkedList<DirectPropertySupport>();
+    private final List<ControlInterfaceSupport.ShortcutSupport> shortcuts = new LinkedList<ControlInterfaceSupport.ShortcutSupport>();
+    private final DeclaredType preferredParent;
+    private final DefaultParentSupport defaultParent;
+    private final DefaultWrapperSupport defaultWrapper;
+    private final DockInfo dockInfo;
+    private final String dockName;
+    private final boolean placeholder;
+    private final DeclaredType ci, w;
+    private final boolean multipleCriteria;
+
+    private ControlSupport(ProcessingEnvironment env) {
+        ci = null;
+        w = null;
+        placeholder = true;
+        this.wrap = (DeclaredType) env.getElementUtils().
+                getTypeElement(Wrap.class.getName()).asType();
+        this.control = (DeclaredType) env.getElementUtils().
+                getTypeElement(Object.class.getName()).asType();
+        defaultParent = null;
+        preferredParent = null;
+        defaultWrapper = null;
+        dockInfo = null;
+        multipleCriteria = false;
+        dockName = Dock.class.getName();
+        //TODO while implementing external wrap superclasses learn to pull interfaces from there
+        interfaces.add(new ControlInterfaceSupport(ControlInterfaceSupport.Kind.ANNOTATION,
+                (DeclaredType) env.getElementUtils().
+                getTypeElement(Mouse.class.getName()).asType(), null, "mouse",
+                null, shortcuts));
+        interfaces.add(new ControlInterfaceSupport(ControlInterfaceSupport.Kind.ANNOTATION,
+                (DeclaredType) env.getElementUtils().
+                getTypeElement(Keyboard.class.getName()).asType(), null, "keyboard",
+                null, shortcuts));
+        interfaces.add(new ControlInterfaceSupport(ControlInterfaceSupport.Kind.ANNOTATION,
+                (DeclaredType) env.getElementUtils().
+                getTypeElement(Drag.class.getName()).asType(), null, "drag",
+                null, shortcuts));
+    }
+
+    ControlSupport(DeclaredType wrap, DeclaredType control, ProcessingEnvironment env) {
+        ci = (DeclaredType) env.getElementUtils().
+                getTypeElement(ControlInterface.class.getName()).asType();
+        w = (DeclaredType) env.getTypeUtils().erasure(env.getElementUtils().
+                getTypeElement(Wrap.class.getName()).asType());
+        placeholder = false;
+        this.wrap = wrap;
+        this.control = control;
+        TypeMirror pWrap = wrap;
+        TypeElement typeEl = (TypeElement) ((DeclaredType) pWrap).asElement();
+        dockInfo = typeEl.getAnnotation(DockInfo.class);
+        AnnotationMirror ciAM = Processor.findAnnotation(typeEl, ControlInterfaces.class);
+        if (ciAM != null) {
+            List<TypeMirror> implemented = new ArrayList<TypeMirror>();
+            findImplementedInterfaces(wrap, implemented, env);
+            List<ExecutableElement> annotated = new ArrayList<ExecutableElement>();
+            findAnnotatedInterfaces(wrap, annotated, env);
+            List<DeclaredType> value = Processor.getClassArrayValue(Processor.getElementValue(ciAM, "value"));
+            List<DeclaredType> encapsulates;
+            AnnotationValue v = Processor.getElementValue(ciAM, "encapsulates");
+            if (v != null) {
+                encapsulates = Processor.getClassArrayValue(v);
+            } else {
+                encapsulates = Collections.emptyList();
+            }
+            List<String> name;
+            v = Processor.getElementValue(ciAM, "name");
+            if (v != null) {
+                name = Processor.getStringArrayValue(v);
+            } else {
+                name = Collections.EMPTY_LIST;
+            }
+            for (int i = 0; i < value.size(); i++) {
+                DeclaredType interfaceType = value.get(i);
+                DeclaredType encapsulatedType = (encapsulates.size() > i) ? encapsulates.get(i) : null;
+                ControlInterfaceSupport.Kind kind = ControlInterfaceSupport.Kind.METHOD;
+                ExecutableElement method = null;
+                for (TypeMirror tm : implemented) {
+                    if (env.getTypeUtils().isSameType(interfaceType, env.getTypeUtils().erasure(tm))) {
+                        if (encapsulatedType == null) {
+                            kind = ControlInterfaceSupport.Kind.SELF;
+                        } else {
+                            if (((DeclaredType) tm).getTypeArguments().size() == 1
+                                    && env.getTypeUtils().isSameType(encapsulatedType,
+                                    ((DeclaredType) tm).getTypeArguments().get(0))) {
+                                kind = ControlInterfaceSupport.Kind.SELF;
+                            }
+                        }
+                    }
+                }
+                for (ExecutableElement mthd : annotated) {
+                    if (env.getTypeUtils().isSameType(interfaceType, env.getTypeUtils().erasure(mthd.getReturnType()))) {
+                        if (encapsulatedType == null) {
+                            kind = ControlInterfaceSupport.Kind.ANNOTATION;
+                            method = mthd;
+                        } else {
+                            AnnotationMirror asAM = Processor.findAnnotation(mthd, As.class);
+                            if (asAM.getElementValues().size() > 0) {
+                                DeclaredType vAE = Processor.getClassValue(Processor.getElementValue(asAM, "value"));
+                                if (!env.getTypeUtils().isSameType(vAE, env.getElementUtils().getTypeElement(Void.class.getName()).asType())
+                                        && env.getTypeUtils().isSameType(vAE, encapsulatedType)) {
+                                    kind = ControlInterfaceSupport.Kind.ANNOTATION;
+                                    method = mthd;
+                                }
+                            }
+                        }
+                    }
+                }
+                interfaces.add(new ControlInterfaceSupport(kind, interfaceType,
+                        encapsulatedType,
+                        (name.size() > i) ? name.get(i) : ("as" + value.get(i).asElement().getSimpleName()),
+                        method, shortcuts));
+            }
+        }
+        AnnotationMirror ppAM = Processor.findAnnotation(typeEl, PreferredParent.class);
+        //PreferredParent ppa = typeEl.getAnnotation(PreferredParent.class);
+        if(ppAM != null) {
+            System.out.println("found a preffered wrap for " + typeEl.toString());
+            preferredParent = Processor.getClassValue(Processor.getElementValue(ppAM, "value"));
+            //prefferedParent = ppa.value();
+        } else {
+            System.out.println("no preffered wrap for " + typeEl.toString());
+            preferredParent = null;
+        }
+        AnnotationMirror mpAM = Processor.findAnnotation(typeEl, MethodProperties.class);
+        AnnotationMirror fpAM = Processor.findAnnotation(typeEl, FieldProperties.class);
+        DefaultParentSupport dParent = null;
+        DefaultWrapperSupport dWrapper = null;
+        boolean origWrap = true;
+        do {
+            for (Element el : typeEl.getEnclosedElements()) {
+                if (el instanceof ExecutableElement) {
+                    ExecutableElement eel = (ExecutableElement) el;
+                    if (dParent == null) {
+                        DefaultParent defaultParentAnn = el.getAnnotation(DefaultParent.class);
+                        if (defaultParentAnn != null) {
+                            dParent = new DefaultParentSupport(eel, defaultParentAnn.value());
+                        }
+                    }
+                    if (dWrapper == null) {
+                        DefaultWrapper defaultWrapperAnn = el.getAnnotation(DefaultWrapper.class);
+                        if (defaultWrapperAnn != null) {
+                            dWrapper = new DefaultWrapperSupport(eel, origWrap);
+                        }
+                    }
+                    ObjectLookup olA = el.getAnnotation(ObjectLookup.class);
+                    if (olA != null) {
+                        if (eel.getParameters().isEmpty()
+                                || !eel.getParameters().get(0).asType().toString().startsWith(Class.class.getName())) { //TODO classname
+                            throw new IllegalStateException("Expect first parameter to ba a class but found "
+                                    + (eel.getParameters().isEmpty() ? "none" : eel.getParameters().get(0).asType().toString()));
+                        }
+                        LookupSupport newLs = new LookupSupport(typeEl, eel, olA.value());
+                        copyParameters(eel, 1, newLs.getParams());
+                        boolean found = false;
+                        for (LookupSupport ls : objectLookups) {
+                            if (ls.equalInTypes(newLs)) {
+                                found = true;
+                                break;
+                            }
+                        }
+                        if (!found) {
+                            objectLookups.add(newLs);
+                        }
+                    }
+                    if (origWrap) {
+                        Property pA = el.getAnnotation(Property.class);
+                        if (pA != null) {
+                            if (eel.getParameters().size() > 0) {
+                                throw new IllegalStateException("Property getter must have no parameters: " + eel.getSimpleName());
+                            }
+                            boolean found = false;
+                            for (DirectPropertySupport dps : propertyMethods) {
+                                if (pA.value().equals(dps.getName())) {
+                                    found = true;
+                                    break;
+                                }
+                            }
+                            if (!found) {
+                                propertyMethods.add(new DirectPropertySupport(pA.value(), eel, pA.waitable()));
+                            }
+                        }
+                    }
+                }
+            }
+            typeEl = (TypeElement) ((DeclaredType) typeEl.getSuperclass()).asElement();
+            origWrap = false;
+        } while (!typeEl.getQualifiedName().toString().equals(Wrap.class.getName()));
+        defaultParent = dParent;
+        defaultWrapper = dWrapper;
+        if (mpAM != null) {
+            addProperties(mpAM, true);
+        }
+        if (fpAM != null) {
+            addProperties(fpAM, false);
+        }
+        multipleCriteria = (dockInfo != null) ? dockInfo.multipleCriteria() : true;
+        if (dockInfo != null && dockInfo.name().length() > 0) {
+            dockName = dockInfo.name();
+        } else {
+            String wrapName = ((TypeElement) wrap.asElement()).getQualifiedName().toString();
+            dockName = wrapName.substring(0, wrapName.lastIndexOf(".")) + "."
+                    + control.asElement().getSimpleName().toString() + "Dock";
+        }
+    }
+
+    public boolean isMultipleCriteria() {
+        return multipleCriteria;
+    }
+
+    private void findImplementedInterfaces(DeclaredType wrap, List<TypeMirror> interfaces, ProcessingEnvironment processingEnv) {
+        if (processingEnv.getTypeUtils().isSameType(w, processingEnv.getTypeUtils().erasure(wrap))) {
+            return;
+        }
+        for (TypeMirror i : ((TypeElement) wrap.asElement()).getInterfaces()) {
+            if (processingEnv.getTypeUtils().isAssignable(i, ci)) {
+                interfaces.add(i);
+            }
+        }
+//        findImplementedInterfaces((DeclaredType)((TypeElement) wrap.asElement()).getSuperclass(),
+//                interfaces, processingEnv);
+    }
+
+    private void findAnnotatedInterfaces(DeclaredType wrap, List<ExecutableElement> interfaces, ProcessingEnvironment processingEnv) {
+        if (processingEnv.getTypeUtils().isSameType(w, processingEnv.getTypeUtils().erasure(wrap))) {
+            return;
+        }
+        for (Element el : ((TypeElement) wrap.asElement()).getEnclosedElements()) {
+            As as = el.getAnnotation(As.class);
+            if (as != null) {
+                if (el instanceof ExecutableElement) {
+                    interfaces.add((ExecutableElement) el);
+                } else {
+                    throw new IllegalStateException("@As applied to something else but a method " + el.toString());
+                }
+            }
+        }
+//        findAnnotatedInterfaces((DeclaredType)((TypeElement) wrap.asElement()).getSuperclass(),
+//                interfaces, processingEnv);
+    }
+
+    public DeclaredType getPreferredParent() {
+        return preferredParent;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public DeclaredType getSuperWrap() {
+        return superWrap;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public boolean isPlaceholder() {
+        return placeholder;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public String getDockName() {
+        return dockName;
+    }
+
+    private void addProperties(AnnotationMirror am, boolean isMethod) {
+        List<String> value = Processor.getStringArrayValue(Processor.getElementValue(am, "value"));
+        List<Boolean> waitable;
+        if(Processor.getElementValue(am, "waitable") != null) {
+            waitable = Processor.getBooleanArrayValue(Processor.getElementValue(am, "waitable"));
+        } else {
+            waitable = Collections.EMPTY_LIST;
+        }
+        List<DeclaredType> types;
+        AnnotationValue v = Processor.getElementValue(am, "types");
+        if (v != null) {
+            types = Processor.getClassArrayValue(v);
+        } else {
+            types = Collections.EMPTY_LIST;
+        }
+        for (int i = 0; i < value.size(); i++) {
+            boolean found = false;
+            for (MappedPropertySupport ps : properties) {
+                if (ps.getName().equals(value.get(i))) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                TypeMirror type;
+                if (types.size() > i) {
+                    type = types.get(i);
+                } else {
+                    type = findType(control, value.get(i), isMethod);
+                }
+                properties.add(new MappedPropertySupport(value.get(i), type, isMethod,
+                        (waitable.size() > i) ? waitable.get(i) : false));
+            }
+        }
+    }
+
+    /**
+     *
+     * @return
+     */
+    public DeclaredType getControl() {
+        return control;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public List<LookupSupport> getObjectLookups() {
+        return objectLookups;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public DeclaredType getWrap() {
+        return wrap;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public List<ControlInterfaceSupport> getInterfaces() {
+        return interfaces;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public List<MappedPropertySupport> getProperties() {
+        return properties;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public List<DirectPropertySupport> getPropertyMethods() {
+        return propertyMethods;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public DefaultParentSupport getDefaultParent() {
+        return defaultParent;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public DefaultWrapperSupport getDefaultWrapper() {
+        return defaultWrapper;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public DockInfo getDockInfo() {
+        return dockInfo;
+    }
+
+    static void copyParameters(ExecutableElement eel, int firstParam, List<SupportParameter> params) {
+        for (int i = firstParam; i < eel.getParameters().size(); i++) {
+            VariableElement ve = eel.getParameters().get(i);
+            params.add(new SupportParameter(ve.getSimpleName().toString(), ve.asType()));
+        }
+    }
+
+    private TypeMirror findType(DeclaredType control, String name, boolean isMethod) {
+        TypeMirror tp = control;
+        TypeElement te;
+        while (tp instanceof DeclaredType && tp.getKind() != TypeKind.NULL) {
+            te = (TypeElement) ((DeclaredType) tp).asElement();
+            for (Element e : te.getEnclosedElements()) {
+                if (e instanceof ExecutableElement) {
+                    ExecutableElement ee = (ExecutableElement) e;
+                    if (isMethod && e.getKind() == ElementKind.METHOD
+                            || !isMethod && e.getKind() == ElementKind.FIELD) {
+                        if (e.getSimpleName().toString().equals(name)
+                                && (!isMethod || ee.getParameters().isEmpty())) {
+                            return e.asType();
+                        }
+                    }
+                }
+            }
+            tp = te.getSuperclass();
+        }
+        return null;
+    }
+
+    //TODO - do a quicksort, at least
+    /**
+     *
+     * @param controls
+     * @param env
+     */
+    public static void linkSuperClasses(List<ControlSupport> controls, ProcessingEnvironment env) {
+        ControlSupport root = null;
+        for (ControlSupport cs : controls) {
+            DeclaredType superWrap = (DeclaredType) ((TypeElement) cs.getWrap().asElement()).getSuperclass();
+            boolean foundOne = false;
+            for (ControlSupport csi : controls) {
+                if (((TypeElement) csi.getWrap().asElement()).getQualifiedName().toString().equals(
+                        ((TypeElement) superWrap.asElement()).getQualifiedName().toString())) {
+                    //that would mean we have found a super wrap among the compiled ones
+                    foundOne = true;
+                    break;
+                }
+            }
+            if (!foundOne) {
+                //the super-wrap is in classpath somewhere
+                //for now only org.jemmy.control.Wrap could be external
+                //TODO improve DockInfo to allow external parents
+                if (((TypeElement) superWrap.asElement()).getQualifiedName().
+                        toString().equals(Wrap.class.getName())) {
+                    if (root == null) {
+                        root = new ControlSupport(env);
+                    }
+                } else {
+                    throw new IllegalStateException("Unknown parent Wrap type "
+                            + ((TypeElement) superWrap.asElement()).getQualifiedName().toString());
+                }
+            }
+            cs.superWrap = superWrap;
+        }
+        controls.add(root);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/src/org/jemmy/support/DefaultParentSupport.java	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.jemmy.support;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+
+/**
+ *
+ * @author shura
+ */
+public class DefaultParentSupport {
+    private final ExecutableElement method;
+    private final String description;
+
+    /**
+     *
+     * @param method
+     * @param description
+     */
+    public DefaultParentSupport(ExecutableElement method, String description) {
+        this.method = method;
+        this.description = description;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public ExecutableElement getMethod() {
+        return method;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/src/org/jemmy/support/DefaultWrapperSupport.java	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.jemmy.support;
+
+import javax.lang.model.element.ExecutableElement;
+
+/**
+ *
+ * @author shura
+ */
+public class DefaultWrapperSupport {
+    private final ExecutableElement method;
+    private final boolean declared;
+
+    /**
+     *
+     * @param method
+     * @param declared
+     */
+    public DefaultWrapperSupport(ExecutableElement method, boolean declared) {
+        this.method = method;
+        this.declared = declared;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public ExecutableElement getMethod() {
+        return method;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public boolean isDeclared() {
+        return declared;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/src/org/jemmy/support/DirectPropertySupport.java	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.jemmy.support;
+
+import javax.lang.model.element.ExecutableElement;
+
+/**
+ *
+ * @author shura
+ */
+public class DirectPropertySupport {
+    private final String name;
+    private final ExecutableElement method;
+    private final boolean waitable;
+
+    /**
+     *
+     * @param name
+     * @param method
+     * @param waitable
+     */
+    public DirectPropertySupport(String name, ExecutableElement method, boolean waitable) {
+        this.name = name;
+        this.method = method;
+        this.waitable = waitable;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public ExecutableElement getMethod() {
+        return method;
+    }
+
+    public boolean isWaitable() {
+        return waitable;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/src/org/jemmy/support/DockGenerator.java	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,706 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.jemmy.support;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.List;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.tools.Diagnostic;
+import javax.tools.JavaFileObject;
+import org.jemmy.control.Wrap;
+import org.jemmy.dock.Dock;
+import org.jemmy.env.Environment;
+import org.jemmy.interfaces.Parent;
+import org.jemmy.lookup.LookupCriteria;
+
+/**
+ *
+ * @author shura
+ */
+class DockGenerator {
+
+    private HashMap<String, String> primitiveTypesSubstitutions =
+            new HashMap<String, String>();
+
+    {
+        primitiveTypesSubstitutions.put(int.class.getName(), Integer.class.getName());
+        primitiveTypesSubstitutions.put(long.class.getName(), Long.class.getName());
+        primitiveTypesSubstitutions.put(float.class.getName(), Float.class.getName());
+        primitiveTypesSubstitutions.put(double.class.getName(), Double.class.getName());
+        primitiveTypesSubstitutions.put(boolean.class.getName(), Boolean.class.getName());
+    }
+    private final ProcessingEnvironment env;
+    private final List<ControlSupport> support;
+
+    public DockGenerator(ProcessingEnvironment processingEnv, List<ControlSupport> docks) {
+        this.env = processingEnv;
+        this.support = docks;
+    }
+
+    void generate() {
+        for (ControlSupport cs : support) {
+            //TODO add DockInfo in every FX Wrap, then uncomment this check
+            //if (cs.getDockInfo() != null) {
+            if (!cs.isPlaceholder()) {
+                TypeElement tel = (TypeElement) cs.getWrap().asElement();
+                env.getMessager().printMessage(Diagnostic.Kind.NOTE,
+                        "Generating dock for " + tel.getQualifiedName());
+                //construct dock class name
+                String dockName = cs.getDockName();
+                String dockPackage = dockName.substring(0, dockName.lastIndexOf("."));
+                String dockShortName = dockName.substring(dockName.lastIndexOf(".") + 1);
+                //superclass
+                TypeElement superTel = (TypeElement) ((DeclaredType) ((TypeElement) cs.getWrap().asElement()).getSuperclass()).asElement();
+                String superDockName = Dock.class.getName();
+                for (ControlSupport csi : support) {
+                    if (env.getTypeUtils().isSameType(csi.getWrap(), superTel.asType())) {
+                        superDockName = csi.getDockName();
+                    }
+                }
+                boolean anonymous = (cs.getDockInfo() != null && cs.getDockInfo().anonymous());
+                StringBuilder body = replace(body_source,
+                        PACKAGE_PLACEHOLDER, dockPackage,
+                        DOCK_PLACEHOLDER, dockShortName,
+                        SUPERDOCK_PLACEHOLDER, superDockName,
+                        WRAP_PLACEHOLDER, tel.getQualifiedName().toString(),
+                        "$SEE_WRAP$", anonymous ? "" : "\t@see " + tel.getQualifiedName().toString());
+                //constructors
+                String controlClassName = ((TypeElement) cs.getControl().asElement()).getQualifiedName().toString();
+                StringBuilder constructors = new StringBuilder();
+                if (cs.getDefaultWrapper() != null) {
+                    constructors.append(replace(control_constructor_source,
+                            DOCK_PLACEHOLDER, dockShortName,
+                            CONTROL_PLACEHOLDER, controlClassName,
+                            "$WRAP_METHOD$", ((TypeElement) cs.getDefaultWrapper().
+                            getMethod().getEnclosingElement()).getQualifiedName()
+                            + "." + cs.getDefaultWrapper().getMethod().
+                            getSimpleName().toString()));
+                }
+                constructors.append(replace(anonymous ? anon_wrap_constructor_source : wrap_constructor_source,
+                        DOCK_PLACEHOLDER, dockShortName,
+                        CONTROL_PLACEHOLDER, controlClassName,
+                        "$PUBLIC$", anonymous ? "protected" : "public",
+                        WRAP_PLACEHOLDER, tel.getQualifiedName().toString()).toString());
+                constructors.append(replace(criteria_constructors_source,
+                        DOCK_PLACEHOLDER, dockShortName,
+                        CONTROL_PLACEHOLDER, controlClassName));
+                boolean needsSubtypeLookups = cs.getDockInfo() != null && cs.getDockInfo().generateSubtypeLookups();
+                if (needsSubtypeLookups) {
+                    constructors.append(replace(criteria_subclass_constructors_source,
+                            DOCK_PLACEHOLDER, dockShortName,
+                            CONTROL_PLACEHOLDER, controlClassName));
+                }
+                String defaultParentMethodCall = null;
+                String defaultParentDescription = null;
+                if (cs.getDefaultParent() != null) {
+                    defaultParentMethodCall = ((TypeElement) cs.getDefaultParent().
+                            getMethod().getEnclosingElement()).getQualifiedName()
+                            + "." + cs.getDefaultParent().getMethod().
+                            getSimpleName().toString();
+                    defaultParentDescription = cs.getDefaultParent().getDescription();
+                    constructors.append(replace(default_parent_criteria_constructors_source,
+                            DOCK_PLACEHOLDER, dockShortName,
+                            CONTROL_PLACEHOLDER, controlClassName,
+                            "$LOOKUP_METHOD$", defaultParentMethodCall,
+                            "$DEFAULT_PARENT_DESCRIPTION$", defaultParentDescription));
+                    if (needsSubtypeLookups) {
+                        constructors.append(replace(default_parent_criteria_subclass_constructors_source,
+                                DOCK_PLACEHOLDER, dockShortName,
+                                CONTROL_PLACEHOLDER, controlClassName,
+                                "$LOOKUP_METHOD$", defaultParentMethodCall,
+                                "$DEFAULT_PARENT_DESCRIPTION$", defaultParentDescription));
+                    }
+                }
+                //object lookup constructors
+                for (int i = 0; i < cs.getObjectLookups().size(); i++) {
+                    StringBuilder declaredParameters = glueParameters(cs.getObjectLookups().get(i).getParams(), false, true);
+                    StringBuilder javadocParameters = glueParameters(cs.getObjectLookups().get(i).getParams(), true, true);
+                    StringBuilder usedParameters = glueParameters(cs.getObjectLookups().get(i).getParams(), false, false);
+                    if (usedParameters.length() > 0) {
+                        usedParameters.insert(0, ", ");
+                        javadocParameters.insert(0, ", ");
+                    }
+                    usedParameters.insert(0, cs.getObjectLookups().get(i).getDeclaringType().getQualifiedName() + "."
+                            + cs.getObjectLookups().get(i).getMethod().getSimpleName() + "($LOOKUP_SUBTYPE$");
+                    usedParameters.append(")");
+                    javadocParameters.insert(0, cs.getObjectLookups().get(i).getDeclaringType().getQualifiedName() + "#"
+                            + cs.getObjectLookups().get(i).getMethod().getSimpleName() + "(" + Class.class.getName());
+                    javadocParameters.append(")");
+                    String comma = (cs.getObjectLookups().get(i).getParams().size() > 0) ? "," : "";
+                    constructors.append(replace(object_lookup_constructors_source,
+                            DOCK_PLACEHOLDER, dockShortName,
+                            CONTROL_PLACEHOLDER, controlClassName,
+                            "$DECLARED_PARAMETERS$", declaredParameters.toString(),
+                            "$USED_PARAMETERS$", usedParameters.toString(),
+                            "$JAVADOC_PARAMETERS$", javadocParameters.toString(),
+                            "$LOOKUP_SUBTYPE$", controlClassName + ".class",
+                            "$LOOKUP_DESCRIPTION$", "by " + cs.getObjectLookups().get(i).getDescription(),
+                            "$COMMA$", comma));
+                    if (needsSubtypeLookups) {
+                        constructors.append(replace(object_lookup_subclass_constructors_source,
+                                DOCK_PLACEHOLDER, dockShortName,
+                                CONTROL_PLACEHOLDER, controlClassName,
+                                "$DECLARED_PARAMETERS$", declaredParameters.toString(),
+                                "$USED_PARAMETERS$", usedParameters.toString(),
+                                "$JAVADOC_PARAMETERS$", javadocParameters.toString(),
+                                "$LOOKUP_SUBTYPE$", "cls",
+                                "$LOOKUP_DESCRIPTION$", "by " + cs.getObjectLookups().get(i).getDescription(),
+                                "$COMMA$", comma));
+                    }
+                    if (cs.getDefaultParent() != null) {
+                        constructors.append(replace(default_parent_object_lookup_constructors_source,
+                                DOCK_PLACEHOLDER, dockShortName,
+                                CONTROL_PLACEHOLDER, controlClassName,
+                                "$LOOKUP_METHOD$", defaultParentMethodCall,
+                                "$DEFAULT_PARENT_DESCRIPTION$", defaultParentDescription,
+                                "$DECLARED_PARAMETERS$", declaredParameters.toString(),
+                                "$USED_PARAMETERS$", usedParameters.toString(),
+                                "$JAVADOC_PARAMETERS$", javadocParameters.toString(),
+                                "$LOOKUP_SUBTYPE$", controlClassName + ".class",
+                                "$LOOKUP_DESCRIPTION$", "by " + cs.getObjectLookups().get(i).getDescription(),
+                                "$COMMA$", comma));
+                        if (needsSubtypeLookups) {
+                            constructors.append(replace(default_parent_object_lookup_subclass_constructors_source,
+                                    DOCK_PLACEHOLDER, dockShortName,
+                                    CONTROL_PLACEHOLDER, controlClassName,
+                                    "$LOOKUP_METHOD$", defaultParentMethodCall,
+                                    "$DEFAULT_PARENT_DESCRIPTION$", defaultParentDescription,
+                                    "$DECLARED_PARAMETERS$", declaredParameters.toString(),
+                                    "$USED_PARAMETERS$", usedParameters.toString(),
+                                    "$JAVADOC_PARAMETERS$", javadocParameters.toString(),
+                                    "$LOOKUP_SUBTYPE$", "cls",
+                                    "$LOOKUP_DESCRIPTION$", "by " + cs.getObjectLookups().get(i).getDescription(),
+                                    "$COMMA$", comma));
+                        }
+                    }
+                }
+                replace(body, "$CONSTRUCTORS$", constructors.toString());
+                //wrapper
+                replace(body, "$WRAP_GETTER$", replace(
+                        anonymous ? anon_wrap_getter_source : wrap_getter_source,
+                        CONTROL_PLACEHOLDER, controlClassName,
+                        WRAP_PLACEHOLDER, tel.getQualifiedName().toString()).toString());
+                //interfaces
+                StringBuilder interfaces = new StringBuilder();
+                for (ControlInterfaceSupport ci : cs.getInterfaces()) {
+//                    boolean skip_shortcuts = false;
+                    DeclaredType innerType = ci.getEncapsulates();
+                    String interface_source_orig;
+                    if (anonymous) {
+                        interface_source_orig = (innerType != null)
+                                ? typed_interface_getter_source
+                                : interface_getter_source;
+                    } else {
+                        switch (ci.getKind()) {
+                            case SELF:
+                                interface_source_orig = (innerType != null)
+                                        ? implemented_typed_interface_getter_source
+                                        : implemented_interface_getter_source;
+                                break;
+                            case ANNOTATION:
+                                if (ci.getMethod().getParameters().isEmpty()) {
+                                    interface_source_orig = (innerType != null)
+                                            ? annotation_typed_interface_getter_source
+                                            : annotation_interface_getter_source;
+                                } else if (ci.getMethod().getParameters().size() == 1) {
+                                    if (innerType == null) {
+                                        throw new IllegalStateException("@As for an untyped interface should have no parameters: "
+                                                + ci.getMethod().toString());
+                                    }
+                                    interface_source_orig = annotation_typed_interface_class_getter_source;
+//                                    skip_shortcuts = true; //a complexity would overweight benefits
+                                } else {
+                                    throw new IllegalStateException("@As method could only have one or no parameters: "
+                                            + ci.getMethod().toString());
+                                }
+                                break;
+                            default:
+                                interface_source_orig = (innerType != null)
+                                        ? typed_interface_getter_source
+                                        : interface_getter_source;
+                                break;
+                        }
+                    }
+                    StringBuilder one_interface_getter = replace(
+                            interface_source_orig,
+                            "$INTERFACE$", ((TypeElement) ci.getType().asElement()).getQualifiedName().toString(),
+                            "$METHOD$", (ci.getMethod() != null) ? ci.getMethod().getSimpleName().toString() : "",
+                            WRAP_PLACEHOLDER, tel.getQualifiedName().toString());
+                    if (innerType != null) {
+                        replace(one_interface_getter, "$INTERFACE_TYPE$",
+                                ((TypeElement) innerType.asElement()).getQualifiedName().toString());
+                    }
+                    String nm;
+                    if (ci.getName() != null) {
+                        nm = ci.getName();
+                    } else {
+                        nm = "as" + ci.getType().asElement().getSimpleName();
+                    }
+                    replace(one_interface_getter, "$INTERFACE_GETTER$", nm);
+                    interfaces.append(one_interface_getter);
+//                    if (!skip_shortcuts) {
+                    for (ControlInterfaceSupport.ShortcutSupport sc : ci.getShortcuts()) {
+                        StringBuilder returnType = new StringBuilder(Processor.toString(sc.getReturnType()));
+                        if (sc.getReturnGenerics().size() > 0) {
+                            returnType.append("<");
+                            for (DeclaredType rgt : sc.getReturnGenerics()) {
+                                returnType.append(((TypeElement) rgt.asElement()).getQualifiedName()).
+                                        append(",");
+                            }
+                            returnType.deleteCharAt(returnType.length() - 1).append(">");
+                        }
+                        StringBuilder scb = replace(shortcut_methods_source,
+                                "$INTERFACE$", ((TypeElement) ci.getType().asElement()).getQualifiedName().toString(),
+                                "$INTERFACE_GETTER$", nm,
+                                "$ORIG_SHORTCUT_NAME$", sc.getMethod().getSimpleName().toString(),
+                                "$NEW_SHORTCUT_NAME$", sc.getName(),
+                                "$DECLARED_PARAMETERS$", glueParameters(sc.getParams(), false, true).toString(),
+                                "$USED_PARAMETERS$", glueParameters(sc.getParams(), false, false).toString(),
+                                "$JAVADOC_PARAMETERS$", glueParameters(sc.getParams(), true, true).toString(),
+                                "$RETURN_TYPE$", returnType.toString(),
+                                "$RETURN_STATEMENT$", sc.getMethod().getReturnType().toString().equals("void") ? "" : "return ");
+                        interfaces.append(scb);
+//                        }
+                    }
+                }
+                replace(body, "$INTERFACES$", interfaces.toString());
+                StringBuilder properties = new StringBuilder();
+                //method properties
+                for (MappedPropertySupport ps : cs.getProperties()) {
+                    String type = (ps.getType() != null)
+                            ? Processor.toString(ps.getType())
+                            : Object.class.getName();
+                    type = (type == null) ? Object.class.getName() : type;
+                    String mptype;
+                    if (primitiveTypesSubstitutions.containsKey(type)) {
+                        mptype = primitiveTypesSubstitutions.get(type);
+                    } else {
+                        mptype = type;
+                    }
+                    properties.append(replace(ps.isMethod() ? method_property_getter_source : field_property_getter_source,
+                            "$PROP_NAME$", ps.getName(),
+                            "$PROP_TYPE$", type,
+                            "$MAP_PROP_TYPE$", mptype,
+                            "$CLASS_PARAMETER$", (ps.getType() != null) ? mptype + ".class, " : "",
+                            "$ORIG_NAME$", ps.getName(),
+                            "$GETTER_NAME$", createGetterName(ps.getName())));
+                    if (ps.isWaitable()) {
+                        properties.append(replace(property_waiter_source,
+                                DOCK_PLACEHOLDER, dockShortName,
+                                "$PROP_NAME$", ps.getName(),
+                                "$PROP_TYPE$", type,
+                                "$MAP_PROP_TYPE$", mptype,
+                                "$WAITER_NAME$", createWaiterName(ps.getName()),
+                                "$GETTER_NAME$", createGetterName(ps.getName())));
+                    }
+                }
+                //declared properties
+                for (DirectPropertySupport ps : cs.getPropertyMethods()) {
+                    String ptype = Processor.toString(ps.getMethod().getReturnType()), mptype;
+                    if (primitiveTypesSubstitutions.containsKey(ptype)) {
+                        mptype = primitiveTypesSubstitutions.get(ptype);
+                    } else {
+                        mptype = ptype;
+                    }
+                    properties.append(replace(
+                            anonymous ? anon_declared_property_getter_source : declared_property_getter_source,
+                            "$PROP_NAME$", ps.getName(),
+                            "$PROP_TYPE$", ptype,
+                            "$MAPPED_PROP_TYPE$", mptype,
+                            "$GETTER_NAME$", createGetterName(ps.getName()),
+                            "$METHOD_NAME$", ps.getMethod().getSimpleName().toString()));
+                    if (ps.isWaitable()) {
+                        properties.append(replace(property_waiter_source,
+                                DOCK_PLACEHOLDER, dockShortName,
+                                "$PROP_NAME$", ps.getName(),
+                                "$PROP_TYPE$", ptype,
+                                "$WAITER_NAME$", createWaiterName(ps.getName()),
+                                "$GETTER_NAME$", createGetterName(ps.getName())));
+                    }
+                }
+                replace(body, "$PROPERTIES$", properties.toString());
+                replace(body, "$MULTIPLE_LOOKUPS$", cs.isMultipleCriteria() ? "..." : "");
+                try {
+                    JavaFileObject f = env.getFiler().
+                            createSourceFile(dockName);
+                    Writer w = f.openWriter();
+                    PrintWriter pw = new PrintWriter(w);
+                    pw.print(body);
+                    pw.flush();
+                    pw.close();
+                } catch (IOException ex) {
+                    env.getMessager().printMessage(Diagnostic.Kind.WARNING, ex.getMessage());
+                }
+            }
+        }
+    }
+
+    private static String createGetterName(String propString) {
+        String result;
+        if (!propString.startsWith("get") && !propString.startsWith("is")) {
+            result = "get" + toUpperCaseCamel(propString);
+        } else {
+            result = propString;
+        }
+        return result.replace('.', '_');
+    }
+
+    private static String createWaiterName(String propString) {
+        String result;
+        if (propString.startsWith("get")) {
+            result = propString.substring(3);
+        } else if (propString.startsWith("is")) {
+            result = propString.substring(2);
+        } else {
+            result = propString;
+        }
+        return "wait" + toUpperCaseCamel(result);
+    }
+
+    private static String toUpperCaseCamel(String camel) {
+        StringBuilder res = new StringBuilder(camel);
+        res.replace(0, 1, res.substring(0, 1).toUpperCase());
+        int dot = res.indexOf(".");
+        while (dot > 0) {
+            res.delete(dot, dot + 1);
+            if (res.length() > dot) {
+                res.replace(dot, dot + 1, res.substring(dot, dot + 1).toUpperCase());
+            }
+            dot = res.indexOf(".");
+        }
+        return res.toString();
+    }
+
+    private StringBuilder replace(String b, String... replacements) {
+        return replace(new StringBuilder(b), replacements);
+    }
+
+    private StringBuilder replace(StringBuilder b, String... replacements) {
+        assert replacements.length % 2 == 0;
+        for (int j = 0; j < replacements.length / 2; j++) {
+            int i;
+            while ((i = b.indexOf(replacements[j * 2])) > -1) {
+                b.replace(i, i + replacements[j * 2].length(), replacements[j * 2 + 1]);
+            }
+        }
+        return b;
+    }
+
+    private StringBuilder glueParameters(List<SupportParameter> params, boolean javadoc, boolean declaration) {
+        StringBuilder result = new StringBuilder();
+        for (int j = 0; j < params.size(); j++) {
+            if (j > 0) {
+                result.append(", ");
+            }
+            if (declaration) {
+                String v = Processor.toString(params.get(j).getType());
+                if (j < params.size() && v.contains("[]")) {
+                    v = v.replace("[]", "...");
+                }
+                result.append(v);
+                if (!javadoc) {
+                    result.append(" ");
+                }
+            }
+            if (!javadoc) {
+                result.append(params.get(j).getName());
+            }
+        }
+        return result;
+    }
+    private static final String CONTROL_PLACEHOLDER = "$CONTROL$";
+    private static final String PACKAGE_PLACEHOLDER = "$PACKAGE$";
+    private static final String SUPERDOCK_PLACEHOLDER = "$SUPERDOCK$";
+    private static final String WRAP_PLACEHOLDER = "$WRAP$";
+    private static final String DOCK_PLACEHOLDER = "$DOCK$";
+    private static final String body_source =
+            "package $PACKAGE$;\n"
+            + "import " + Wrap.class.getName() + ";\n"
+            + "import " + Parent.class.getName() + ";\n"
+            + "import " + LookupCriteria.class.getName() + ";\n"
+            + "import " + Environment.class.getName() + ";\n"
+            + "/**\n"
+            + "This is a convenience class generated by information available through annotations in class $WRAP$\n"
+            + "$SEE_WRAP$\n"
+            + "*/\n"
+            + "public class $DOCK$ extends $SUPERDOCK$ {\n"
+            + "$CONSTRUCTORS$"
+            + "$WRAP_GETTER$"
+            + "$INTERFACES$"
+            + "$PROPERTIES$"
+            + "}";
+    private static final String control_constructor_source =
+            "\t/**Creates dock for a previously found control\n"
+            + "\t@see Environment*/\n"
+            + "\tpublic $DOCK$(Environment env, $CONTROL$ control) {\n"
+            + "\t\tsuper($WRAP_METHOD$(env, $CONTROL$.class, control));\n"
+            + "\t}\n";
+    private static final String anon_wrap_constructor_source =
+            "\t/**Creates dock for a wrapped control*/\n"
+            + "\t$PUBLIC$ $DOCK$(Wrap<? extends $CONTROL$> wrap) {\n"
+            + "\t\tsuper(wrap);\n"
+            + "\t}\n";
+    private static final String wrap_constructor_source =
+            "\t/**Creates dock for a wrapped control\n"
+            + "\t@see $WRAP$*/\n"
+            + "\t$PUBLIC$ $DOCK$(Wrap<? extends $CONTROL$> wrap) {\n"
+            + "\t\tsuper(wrap);\n"
+            + "\t}\n";
+    private static final String criteria_constructors_source =
+            "\t/**Looks for an <code>index</code>'th <code>$CONTROL$</code> by a criteria"
+            + " within <code>parent</code>\n"
+            + "\t@see LookupCriteria*/\n"
+            + "\tpublic $DOCK$(Parent<? super $CONTROL$> parent, int index, LookupCriteria<$CONTROL$>$MULTIPLE_LOOKUPS$ criteria) {\n"
+            + "\t\tthis(lookup(parent, $CONTROL$.class, index, criteria));\n"
+            + "\t}\n"
+            + "\t/**Looks for a <code>$CONTROL$</code> by a criteria"
+            + " within <code>parent</code>\n"
+            + "\t@see LookupCriteria*/\n"
+            + "\tpublic $DOCK$(Parent<? super $CONTROL$> parent, LookupCriteria<$CONTROL$>$MULTIPLE_LOOKUPS$ criteria) {\n"
+            + "\t\tthis(parent, 0, criteria);\n"
+            + "\t}\n";
+    private static final String object_lookup_constructors_source =
+            "\t/**Looks for an <code>index</code>'th <code>$CONTROL$</code> $LOOKUP_DESCRIPTION$"
+            + " within <code>parent</code>\n"
+            + "\t@see $JAVADOC_PARAMETERS$*/\n"
+            + "\tpublic $DOCK$(Parent<? super $CONTROL$> parent, int index$COMMA$ $DECLARED_PARAMETERS$) {\n"
+            + "\t\tthis(parent, index, $USED_PARAMETERS$);\n"
+            + "\t}\n"
+            + "\t/**Looks for a <code>$CONTROL$</code> $LOOKUP_DESCRIPTION$"
+            + " within <code>parent</code>\n"
+            + "\t@see $JAVADOC_PARAMETERS$*/\n"
+            + "\tpublic $DOCK$(Parent<? super $CONTROL$> parent$COMMA$ $DECLARED_PARAMETERS$) {\n"
+            + "\t\tthis(parent, $USED_PARAMETERS$);\n"
+            + "\t}\n";
+    private static final String default_parent_criteria_constructors_source =
+            "\t/**Looks for a <code>$CONTROL$</code> by a criteria"
+            + " within $DEFAULT_PARENT_DESCRIPTION$\n"
+            + "\t@see LookupCriteria*/\n"
+            + "\tpublic $DOCK$(LookupCriteria<$CONTROL$>$MULTIPLE_LOOKUPS$ criteria) {\n"
+            + "\t\tthis(0, criteria);\n"
+            + "\t}\n"
+            + "\t/**Looks for an <code>index</code>'th <code>$CONTROL$</code> by a criteria"
+            + " within $DEFAULT_PARENT_DESCRIPTION$\n"
+            + "\t@see LookupCriteria*/\n"
+            + "\tpublic $DOCK$(int index, LookupCriteria<$CONTROL$>$MULTIPLE_LOOKUPS$ criteria) {\n"
+            + "\t\tthis($LOOKUP_METHOD$($CONTROL$.class), index, criteria);\n"
+            + "\t}\n";
+    private static final String default_parent_object_lookup_constructors_source =
+            "\t/**Looks for a <code>$CONTROL$</code> $LOOKUP_DESCRIPTION$"
+            + " within $DEFAULT_PARENT_DESCRIPTION$\n"
+            + "\t@see $JAVADOC_PARAMETERS$*/\n"
+            + "\tpublic $DOCK$($DECLARED_PARAMETERS$) {\n"
+            + "\t\tthis(0, $USED_PARAMETERS$);\n"
+            + "\t}\n"
+            + "\t/**Looks for an <code>index</code>'th <code>$CONTROL$</code> $LOOKUP_DESCRIPTION$"
+            + " within $DEFAULT_PARENT_DESCRIPTION$\n"
+            + "\t@see $JAVADOC_PARAMETERS$*/\n"
+            + "\tpublic $DOCK$(int index$COMMA$ $DECLARED_PARAMETERS$) {\n"
+            + "\t\tthis($LOOKUP_METHOD$($CONTROL$.class), index, $USED_PARAMETERS$);\n"
+            + "\t}\n";
+    private static final String criteria_subclass_constructors_source =
+            "\t/**Looks for an <code>index</code>'th <code>SUBCLASS</code> by a criteria"
+            + " within <code>parent</code>\n"
+            + "\t@see LookupCriteria*/\n"
+            + "\tpublic <SUBCLASS extends $CONTROL$> $DOCK$(Parent<? super $CONTROL$> parent, Class<SUBCLASS> cls, int index, LookupCriteria<SUBCLASS>$MULTIPLE_LOOKUPS$ criteria) {\n"
+            + "\t\tthis(lookup(parent, cls, index, criteria));\n"
+            + "\t}\n"
+            + "\t/**Looks for a <code>SUBCLASS</code> by a criteria"
+            + " within <code>parent</code>\n"
+            + "\t@see LookupCriteria*/\n"
+            + "\tpublic <SUBCLASS extends $CONTROL$> $DOCK$(Parent<? super $CONTROL$> parent, Class<SUBCLASS> cls, LookupCriteria<SUBCLASS>$MULTIPLE_LOOKUPS$ criteria) {\n"
+            + "\t\tthis(parent, cls, 0, criteria);\n"
+            + "\t}\n";
+    private static final String object_lookup_subclass_constructors_source =
+            "\t/**Looks for an <code>index</code>'th <code>SUBCLASS</code> $LOOKUP_DESCRIPTION$"
+            + " within <code>parent</code>\n"
+            + "\t@see $JAVADOC_PARAMETERS$*/\n"
+            + "\tpublic <SUBCLASS extends $CONTROL$> $DOCK$(Parent<? super $CONTROL$> parent, Class<SUBCLASS> cls, int index$COMMA$ $DECLARED_PARAMETERS$) {\n"
+            + "\t\tthis(parent, cls, index, $USED_PARAMETERS$);\n"
+            + "\t}\n"
+            + "\t/**Looks for a <code>SUBCLASS</code> $LOOKUP_DESCRIPTION$"
+            + " within <code>parent</code>\n"
+            + "\t@see $JAVADOC_PARAMETERS$*/\n"
+            + "\tpublic <SUBCLASS extends $CONTROL$> $DOCK$(Parent<? super $CONTROL$> parent, Class<SUBCLASS> cls$COMMA$ $DECLARED_PARAMETERS$) {\n"
+            + "\t\tthis(parent, cls, $USED_PARAMETERS$);\n"
+            + "\t}\n";
+    private static final String default_parent_criteria_subclass_constructors_source =
+            "\t/**Looks for a <code>SUBCLASS</code> by a criteria"
+            + " within $DEFAULT_PARENT_DESCRIPTION$\n"
+            + "\t@see LookupCriteria*/\n"
+            + "\tpublic <SUBCLASS extends $CONTROL$> $DOCK$(Class<SUBCLASS> cls, LookupCriteria<SUBCLASS>$MULTIPLE_LOOKUPS$ criteria) {\n"
+            + "\t\tthis(cls, 0, criteria);\n"
+            + "\t}\n"
+            + "\t/**Looks for an <code>index</code>'th <code>SUBCLASS</code> by a criteria"
+            + " within $DEFAULT_PARENT_DESCRIPTION$\n"
+            + "\t@see LookupCriteria*/\n"
+            + "\tpublic <SUBCLASS extends $CONTROL$> $DOCK$(Class<SUBCLASS> cls, int index, LookupCriteria<SUBCLASS>$MULTIPLE_LOOKUPS$ criteria) {\n"
+            + "\t\tthis($LOOKUP_METHOD$(cls), cls, index, criteria);\n"
+            + "\t}\n";
+    private static final String default_parent_object_lookup_subclass_constructors_source =
+            "\t/**Looks for a <code>SUBCLASS</code> $LOOKUP_DESCRIPTION$"
+            + " within $DEFAULT_PARENT_DESCRIPTION$\n"
+            + "\t@see $JAVADOC_PARAMETERS$*/\n"
+            + "\tpublic <SUBCLASS extends $CONTROL$> $DOCK$(Class<SUBCLASS> cls$COMMA$ $DECLARED_PARAMETERS$) {\n"
+            + "\t\tthis(cls, 0, $USED_PARAMETERS$);\n"
+            + "\t}\n"
+            + "\t/**Looks for an <code>index</code>'th <code>SUBCLASS</code> $LOOKUP_DESCRIPTION$"
+            + " within $DEFAULT_PARENT_DESCRIPTION$\n"
+            + "\t@see $JAVADOC_PARAMETERS$*/\n"
+            + "\tpublic <SUBCLASS extends $CONTROL$> $DOCK$(Class<SUBCLASS> cls, int index$COMMA$ $DECLARED_PARAMETERS$) {\n"
+            + "\t\tthis($LOOKUP_METHOD$(cls), cls, index, $USED_PARAMETERS$);\n"
+            + "\t}\n";
+    private static final String wrap_getter_source =
+            "\t/**Returns wrap\n"
+            + "\t@see $WRAP$*/\n"
+            + "\t@Override\n"
+            + "\tpublic $WRAP$<? extends $CONTROL$> wrap() {\n"
+            + "\t\treturn ($WRAP$<? extends $CONTROL$>)super.wrap();\n"
+            + "\t}\n"
+            + "\t/**Returns control*/\n"
+            + "\t@Override\n"
+            + "\tpublic $CONTROL$ control() {\n"
+            + "\t\treturn wrap().getControl();\n"
+            + "\t}\n";
+    private static final String anon_wrap_getter_source =
+            "\t/**Returns wrap\n"
+            + "\t@see Wrap*/\n"
+            + "\t@Override\n"
+            + "\tpublic Wrap<? extends $CONTROL$> wrap() {\n"
+            + "\t\treturn (Wrap<? extends $CONTROL$>)super.wrap();\n"
+            + "\t}\n"
+            + "\t/**Returns control*/\n"
+            + "\t@Override\n"
+            + "\tpublic $CONTROL$ control() {\n"
+            + "\t\treturn wrap().getControl();\n"
+            + "\t}\n";
+    private static final String interface_getter_source =
+            "\t/**Allows to use as <code>$INTERFACE$</code>\n"
+            + "\t@see $INTERFACE$*/\n"
+            + "\tpublic $INTERFACE$ $INTERFACE_GETTER$() {\n"
+            + "\t\treturn wrap().as($INTERFACE$.class);\n"
+            + "\t}\n";
+    private static final String implemented_interface_getter_source =
+            "\t/**Allows to use as <code>$INTERFACE$</code>\n"
+            + "\t@see $INTERFACE$*/\n"
+            + "\tpublic $INTERFACE$ $INTERFACE_GETTER$() {\n"
+            + "\t\treturn wrap();\n"
+            + "\t}\n";
+    private static final String annotation_interface_getter_source =
+            "\t/**Allows to use as <code>$INTERFACE$</code>\n"
+            + "\t@see $INTERFACE$\n"
+            + "\t@see $WRAP$#$METHOD$()*/\n"
+            + "\tpublic $INTERFACE$ $INTERFACE_GETTER$() {\n"
+            + "\t\treturn wrap().$METHOD$();\n"
+            + "\t}\n";
+    private static final String typed_interface_getter_source =
+            "\t/**Allows to use as <code>$INTERFACE$&lt;$INTERFACE_TYPE$&gt;</code>\n"
+            + "\t@see $INTERFACE$*/\n"
+            + "\tpublic $INTERFACE$<$INTERFACE_TYPE$> $INTERFACE_GETTER$() {\n"
+            + "\t\treturn wrap().as($INTERFACE$.class, $INTERFACE_TYPE$.class);\n"
+            + "\t}\n";
+    private static final String implemented_typed_interface_getter_source =
+            "\t/**Allows to use as <code>$INTERFACE$&lt;$INTERFACE_TYPE$&gt;</code>\n"
+            + "\t@see $INTERFACE$*/\n"
+            + "\tpublic $INTERFACE$<$INTERFACE_TYPE$> $INTERFACE_GETTER$() {\n"
+            + "\t\treturn wrap();\n"
+            + "\t}\n";
+    private static final String annotation_typed_interface_getter_source =
+            "\t/**Allows to use as <code>$INTERFACE$&lt;$INTERFACE_TYPE$&gt;</code>\n"
+            + "\t@see $INTERFACE$\n"
+            + "\t@see $WRAP$#$METHOD$()*/\n"
+            + "\tpublic $INTERFACE$<$INTERFACE_TYPE$> $INTERFACE_GETTER$() {\n"
+            + "\t\treturn wrap().$METHOD$();\n"
+            + "\t}\n";
+    private static final String annotation_typed_interface_class_getter_source =
+            "\t/**Allows to use as <code>$INTERFACE$&lt;$INTERFACE_TYPE$&gt;</code>\n"
+            + "\t@see $INTERFACE$\n"
+            + "\t@see #$INTERFACE_GETTER$(Class)\n"
+            + "\t@see $WRAP$#$METHOD$(Class)*/\n"
+            + "\tpublic $INTERFACE$<$INTERFACE_TYPE$> $INTERFACE_GETTER$() {\n"
+            + "\t\treturn wrap().$METHOD$($INTERFACE_TYPE$.class);\n"
+            + "\t}\n"
+            + "\t/**Allows to use as <code>$INTERFACE$&lt;T&gt;</code>\n"
+            + "\t@see $INTERFACE$\n"
+            + "\t@see #$INTERFACE_GETTER$()\n"
+            + "\t@see $WRAP$#$METHOD$(Class)*/\n"
+            + "\tpublic <T extends $INTERFACE_TYPE$> $INTERFACE$<T> $INTERFACE_GETTER$(Class<T> type) {\n"
+            + "\t\treturn wrap().$METHOD$(type);\n"
+            + "\t}\n";
+    private static final String property_getter_source =
+            "\t/**Returns a result of <code>$PROP_NAME$</code> method*/\n"
+            + "\tpublic $PROP_TYPE$ $GETTER_NAME$() {\n"
+            + "\t\treturn wrap().getProperty($CLASS_PARAMETER$\"$PROP_NAME$\");\n"
+            + "\t}\n";
+    private static final String method_property_getter_source =
+            "\t/**Returns a result of <code>$PROP_NAME$</code> method*/\n"
+            + "\tpublic $PROP_TYPE$ $GETTER_NAME$() {\n"
+            + "\t\treturn new org.jemmy.action.GetAction<$MAP_PROP_TYPE$>() {\n"
+            + "\t\t\t@Override\n"
+            + "\t\t\tpublic void run(Object... parameters) {\n"
+            + "\t\t\t\tsetResult(control().$ORIG_NAME$());\n"
+            + "\t\t\t}\n"
+            + "\t\t}.dispatch(wrap().getEnvironment());\n"
+            + "\t}\n";
+    private static final String field_property_getter_source =
+            "\t/**Returns a result of <code>$PROP_NAME$</code> method*/\n"
+            + "\tpublic $PROP_TYPE$ $GETTER_NAME$() {\n"
+            + "\t\treturn new org.jemmy.action.GetAction<$MAP_PROP_TYPE$>() {\n"
+            + "\t\t\t@Override\n"
+            + "\t\t\tpublic void run(Object... parameters) {\n"
+            + "\t\t\t\tsetResult(control().$ORIG_NAME$);\n"
+            + "\t\t\t}\n"
+            + "\t\t}.dispatch(wrap().getEnvironment());\n"
+            + "\t}\n";
+    private static final String property_waiter_source =
+            "\t/**Waits for a \"<code>$PROP_NAME$</code>\" property to be equal to a parameter\n"
+            + "\t@throws org.jemmy.TimeoutExpiredException*/\n"
+            + "\tpublic void $WAITER_NAME$($PROP_TYPE$ expected) {\n"
+            + "\t\twrap().waitState(new org.jemmy.timing.State<$MAP_PROP_TYPE$>() {\n"
+            + "\t\t\tpublic $PROP_TYPE$ reached() {\n"
+            + "\t\t\t\treturn $DOCK$.this.$GETTER_NAME$();\n"
+            + "\t\t\t}\n"
+            + "\t\t}, expected);\n"
+            + "\t}\n";
+    private static final String declared_property_getter_source =
+            "\t/**Returns $PROP_NAME$ property*/\n"
+            + "\tpublic $PROP_TYPE$ $GETTER_NAME$() {\n"
+            + "\t\treturn wrap().$METHOD_NAME$();\n"
+            + "\t}\n";
+    private static final String anon_declared_property_getter_source =
+            "\t/**Returns $PROP_NAME$ property*/\n"
+            + "\tpublic $PROP_TYPE$ $GETTER_NAME$() {\n"
+            + "\t\treturn wrap().getProperty($MAPPED_PROP_TYPE$.class, \"$PROP_NAME$\");\n"
+            + "\t}\n";
+    private static final String shortcut_methods_source =
+            "\t/**Calls <code>$INTERFACE_GETTER$().$ORIG_SHORTCUT_NAME$($DECLARED_PARAMETERS$);</code>\n"
+            + "\t@see $INTERFACE$#$ORIG_SHORTCUT_NAME$($JAVADOC_PARAMETERS$)*/\n"
+            + "\tpublic $RETURN_TYPE$ $NEW_SHORTCUT_NAME$($DECLARED_PARAMETERS$) {\n"
+            + "\t\t $RETURN_STATEMENT$$INTERFACE_GETTER$().$ORIG_SHORTCUT_NAME$($USED_PARAMETERS$);\n"
+            + "\t}\n";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/src/org/jemmy/support/DumpGenerator.java	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.jemmy.support;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.TypeElement;
+import javax.tools.StandardLocation;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ *
+ * @author shura
+ */
+class DumpGenerator {
+
+    public static final String ROOT = "root";
+    public static final String CONTROL = "control";
+    public static final String WRAP = "wrap";
+    public static final String SUPER_WRAP = "super-wrap";
+    public static final String DOCK_NAME = "dock-name";
+    public static final String PREFERRED_PARENT = "preferred-parent";
+    public static final String DEFAULT_PARENT = "default-parent";
+    public static final String METHOD = "method";
+    public static final String CLASS = "class";
+    public static final String DESCRIPTION = "description";
+    public static final String DEFAULT_WRAPPER = "default-wrapper";
+    public static final String INTERFACES = "interfaces";
+    public static final String INTERFACE = "interface";
+    public static final String TYPE = "type";
+    public static final String ENCAPSULATES = "encapsulates";
+    public static final String NAME = "name";
+    public static final String LOOKUPS = "lookups";
+    public static final String LOOKUP = "lookup";
+    public static final String DECLARING = "declaring";
+    public static final String PARAMETERS = "parameters";
+    public static final String PARAMETER = "parameter";
+    public static final String PROPERTIES = "properties";
+    public static final String PROPERTY = "property";
+
+    private final ProcessingEnvironment processingEnv;
+    private final List<ControlSupport> docks;
+
+    public DumpGenerator(ProcessingEnvironment processingEnv, List<ControlSupport> docks) {
+        this.processingEnv = processingEnv;
+        this.docks = docks;
+    }
+
+    void generate() throws ParserConfigurationException, IOException, TransformerException {
+        DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
+        DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
+        Document doc = docBuilder.newDocument();
+
+        Element root = doc.createElement(ROOT);
+        doc.appendChild(root);
+
+        for (ControlSupport cs : docks) {
+            Element cse = doc.createElement(CONTROL);
+            root.appendChild(cse);
+            cse.setAttribute(WRAP, ((TypeElement) cs.getWrap().asElement()).getQualifiedName().toString());
+            if (cs.getSuperWrap() != null) {
+                cse.setAttribute(SUPER_WRAP, ((TypeElement) cs.getSuperWrap().asElement()).getQualifiedName().toString());
+            }
+            cse.setAttribute(CONTROL, ((TypeElement) cs.getControl().asElement()).getQualifiedName().toString());
+            cse.setAttribute(DOCK_NAME, cs.getDockName());
+            if(cs.getPreferredParent() != null) {
+                cse.setAttribute(PREFERRED_PARENT, ((TypeElement) cs.getPreferredParent().asElement()).getQualifiedName().toString());
+            }
+            if (cs.getDefaultParent() != null) {
+                Element dp = doc.createElement(DEFAULT_PARENT);
+                cse.appendChild(dp);
+                dp.setAttribute(METHOD, cs.getDefaultParent().getMethod().getSimpleName().toString());
+                dp.setAttribute(CLASS, ((TypeElement) cs.getDefaultParent().getMethod().getEnclosingElement()).getQualifiedName().toString());
+                dp.setAttribute(DESCRIPTION, cs.getDefaultParent().getDescription());
+            }
+            if (cs.getDefaultWrapper() != null) {
+                Element dw = doc.createElement(DEFAULT_WRAPPER);
+                cse.appendChild(dw);
+                dw.setAttribute(METHOD, cs.getDefaultWrapper().getMethod().getSimpleName().toString());
+                dw.setAttribute(CLASS, ((TypeElement) cs.getDefaultWrapper().getMethod().getEnclosingElement()).getQualifiedName().toString());
+            }
+            Element les = doc.createElement(INTERFACES);
+            cse.appendChild(les);
+            for (ControlInterfaceSupport ci : cs.getInterfaces()) {
+                Element cie = doc.createElement(INTERFACE);
+                les.appendChild(cie);
+                cie.setAttribute(TYPE, Processor.toStringDollar(ci.getType()));
+                if (ci.getEncapsulates() != null) {
+                    cie.setAttribute(ENCAPSULATES, Processor.toStringDollar(ci.getEncapsulates()));
+                }
+                cie.setAttribute(NAME, ci.getName());
+            }
+            Element cies = doc.createElement(LOOKUPS);
+            cse.appendChild(cies);
+            for (LookupSupport l : cs.getObjectLookups()) {
+                Element le = doc.createElement(LOOKUP);
+                cies.appendChild(le);
+                le.setAttribute(METHOD, l.getMethod().getSimpleName().toString());
+                le.setAttribute(DECLARING, l.getDeclaringType().getQualifiedName().toString());
+                le.setAttribute(DESCRIPTION, l.getDescription());
+                Element lpes = doc.createElement(PARAMETERS);
+                le.appendChild(lpes);
+                for (SupportParameter sp : l.getParams()) {
+                    Element spe = doc.createElement(PARAMETER);
+                    lpes.appendChild(spe);
+                    spe.setAttribute(TYPE, Processor.toStringDollar(sp.getType()));
+                    spe.setAttribute(NAME, sp.getName());
+                }
+            }
+            Element pes = doc.createElement(PROPERTIES);
+            cse.appendChild(pes);
+            for (MappedPropertySupport mp : cs.getProperties()) {
+                Element mpe = doc.createElement(PROPERTY);
+                pes.appendChild(mpe);
+                mpe.setAttribute(NAME, mp.getName());
+                mpe.setAttribute(TYPE, Processor.toStringDollar(mp.getType()));//TODO only one StringTypeGetter needed
+            }
+            for (DirectPropertySupport mp : cs.getPropertyMethods()) {
+                Element mpe = doc.createElement(PROPERTY);
+                pes.appendChild(mpe);
+                mpe.setAttribute(NAME, mp.getName());
+                mpe.setAttribute(TYPE, Processor.toStringDollar(mp.getMethod().getReturnType()));
+            }
+        }
+
+        TransformerFactory transfac = TransformerFactory.newInstance();
+        Transformer trans = transfac.newTransformer();
+        trans.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
+        trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+        trans.setOutputProperty(OutputKeys.INDENT, "yes");
+
+        OutputStream out = processingEnv.getFiler().
+                createResource(StandardLocation.SOURCE_OUTPUT, "", "support.xml").
+                openOutputStream();
+
+        //create string from xml tree
+        StreamResult result = new StreamResult(out);
+        DOMSource source = new DOMSource(doc);
+        trans.transform(source, result);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/src/org/jemmy/support/LookupSupport.java	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.jemmy.support;
+
+import java.util.LinkedList;
+import java.util.List;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+
+/**
+ *
+ * @author shura
+ */
+public class LookupSupport {
+    private final List<SupportParameter> params = new LinkedList<SupportParameter>();
+    private final ExecutableElement method;
+    private final String description;
+    private final TypeElement cls;
+
+    /**
+     *
+     * @param cls
+     * @param method
+     * @param description
+     */
+    public LookupSupport(TypeElement cls, ExecutableElement method, String description) {
+        this.cls = cls;
+        this.method = method;
+        this.description = description;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public TypeElement getDeclaringType() {
+        return cls;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public List<SupportParameter> getParams() {
+        return params;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public ExecutableElement getMethod() {
+        return method;
+    }
+
+    /**
+     *
+     * @param another
+     * @return
+     */
+    public boolean equalInTypes(LookupSupport another) {
+        if(another.getParams().size() == getParams().size()) {
+            for (int i = 0; i < getParams().size(); i++) {
+                if(!another.getParams().get(i).getType().toString()
+                        .equals(getParams().get(i).getType().toString())) {
+                    return false;
+                }
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/src/org/jemmy/support/MappedPropertySupport.java	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.jemmy.support;
+
+import javax.lang.model.type.TypeMirror;
+
+/**
+ *
+ * @author shura
+ */
+public class MappedPropertySupport {
+    private final TypeMirror type;
+    private final String name;
+    private final boolean waitable;
+    private final boolean method;
+
+    public MappedPropertySupport(String name, TypeMirror type, boolean method, boolean waitable) {
+        this.type = type;
+        this.name = name;
+        this.waitable = waitable;
+        this.method = method;
+    }
+
+
+    /**
+     *
+     * @return
+     */
+    public TypeMirror getType() {
+        return type;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public boolean isMethod() {
+        return method;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public boolean isWaitable() {
+        return waitable;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/src/org/jemmy/support/Processor.java	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.jemmy.support;
+
+import java.util.*;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+import javax.lang.model.util.SimpleAnnotationValueVisitor6;
+import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.tools.Diagnostic;
+import org.jemmy.control.ControlType;
+
+/**
+ * JemmySupport annotation processor.
+ * One would supposed to hook this to the compilation process by adding next
+ * arguments to <code>javac</code> call
+ * <pre>
+ * -processor Processor -Aactions=&lt;actions&gt; -s &lt;destination&gt;
+ * </pre>
+ * where <code>actions</code> could, at the moment, contain <code>"docks"</code>
+ * and/or <code>"dump"</code>.<br/>
+ * <code>"docks"</code> means that dock classes will be generated into a dir passed by
+ * <code>-s</code> option. <br/>
+ * <code>"dump"</code> means that there will be <code>support.xml</code> file generated
+ * into a dir passed by <code>-s</code> option. <br/>
+ *
+ * @author shura
+ */
+@SupportedSourceVersion(SourceVersion.RELEASE_6)
+public class Processor extends AbstractProcessor {
+    private static final String DOCKS = "docks";
+    private static final String DUMP = "dump";
+
+    private static final String ACTIONS = "actions";
+    private final Set<String> types = new HashSet<String>();
+    private final Set<String> options = new HashSet<String>();
+
+    /**
+     *
+     */
+    public Processor() {
+        types.add(ControlType.class.getName());
+        options.add(ACTIONS);
+    }
+
+    ProcessingEnvironment getProccessingEnvironment() {
+        return processingEnv;
+    }
+
+    @Override
+    public Set<String> getSupportedAnnotationTypes() {
+        return types;
+    }
+    private static boolean onlyOnce = false;
+
+    @Override
+    public boolean process(Set<? extends TypeElement> set, RoundEnvironment re) {
+        if (onlyOnce) {
+            return false;
+        }
+        onlyOnce = true;
+        List<ControlSupport> docks = new LinkedList<ControlSupport>();
+        for (Element e : re.getElementsAnnotatedWith(ControlType.class)) {
+            processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
+                    "Loading support information from " + toString(e.asType()));
+            for (TypeMirror c : getClassArrayValue(getElementValue(
+                    findAnnotations(e, ControlType.class).get(0), "value"))) {
+                docks.add(new ControlSupport((DeclaredType) e.asType(), (DeclaredType) c, processingEnv));
+            }
+        }
+        ControlSupport.linkSuperClasses(docks, processingEnv);
+        String actions = processingEnv.getOptions().get(ACTIONS);
+        if (actions.contains(DOCKS)) {
+            new DockGenerator(processingEnv, docks).generate();
+        }
+        if (actions.contains(DUMP)) {
+            try {
+                new DumpGenerator(processingEnv, docks).generate();
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public Set<String> getSupportedOptions() {
+        return options;
+    }
+
+    static List<AnnotationMirror> findAnnotations(Element e, Class annotationType) {
+        List<AnnotationMirror> res = new LinkedList<AnnotationMirror>();
+        for (AnnotationMirror am : e.getAnnotationMirrors()) {
+            if (am.getAnnotationType().toString().equals(annotationType.getName())) {
+                res.add(am);
+            }
+        }
+        return res;
+    }
+
+    static AnnotationMirror findAnnotation(Element e, Class annotationType) {
+        List<AnnotationMirror> res = findAnnotations(e, annotationType);
+        if (res.size() > 0) {
+            return res.get(0);
+        } else {
+            return null;
+        }
+    }
+
+    static AnnotationValue getElementValue(AnnotationMirror am, String name) {
+        Map<? extends ExecutableElement, ? extends AnnotationValue> values = am.getElementValues();
+        for (ExecutableElement ee : values.keySet()) {
+            if (ee.getSimpleName().contentEquals(name)) {
+                return values.get(ee);
+            }
+        }
+        return null;
+    }
+    private static final StringTypeGetter stringTypeVisitor = new StringTypeGetter(false);
+
+    static String toString(TypeMirror type) {
+        return type.accept(stringTypeVisitor, null);
+    }
+    private static final StringTypeGetter stringTypeVisitorDollar = new StringTypeGetter(true);
+
+    static String toStringDollar(TypeMirror type) {
+        return type.accept(stringTypeVisitorDollar, null);
+    }
+    private static final StringValueGetter stringValueVisitor = new StringValueGetter();
+
+    static String getStringValue(AnnotationValue v) {
+        return v.accept(stringValueVisitor, null);
+    }
+    private static final StringArrayValueGetter stringArrayValueVisitor = new StringArrayValueGetter();
+
+    static List<String> getStringArrayValue(AnnotationValue v) {
+        return v.accept(stringArrayValueVisitor, null);
+    }
+    private static final BooleanArrayValueGetter booleanArrayValueVisitor = new BooleanArrayValueGetter();
+
+    static List<Boolean> getBooleanArrayValue(AnnotationValue v) {
+        return v.accept(booleanArrayValueVisitor, null);
+    }
+
+    private static final ClassArrayValueGetter classArrayValueVisitor = new ClassArrayValueGetter();
+
+    static List<DeclaredType> getClassArrayValue(AnnotationValue v) {
+        return v.accept(classArrayValueVisitor, null);
+    }
+
+    private static final ClassValueGetter classValueVisitor = new ClassValueGetter();
+
+    static DeclaredType getClassValue(AnnotationValue v) {
+        return (DeclaredType) v.accept(classValueVisitor, null);
+    }
+
+    private static class ClassArrayValueGetter extends SimpleAnnotationValueVisitor6<List<DeclaredType>, Object> {
+
+        @Override
+        public List<DeclaredType> visitArray(List<? extends AnnotationValue> list, Object p) {
+            List<DeclaredType> result = new ArrayList<DeclaredType>();
+            for (AnnotationValue av : list) {
+                result.add((DeclaredType) av.accept(new ClassValueGetter(), null));
+            }
+            return result;
+        }
+    }
+
+    private static class StringArrayValueGetter extends SimpleAnnotationValueVisitor6<List<String>, Object> {
+
+        @Override
+        public List<String> visitArray(List<? extends AnnotationValue> list, Object p) {
+            List<String> result = new ArrayList<String>();
+            for (AnnotationValue av : list) {
+                result.add(av.accept(new StringValueGetter(), null));
+            }
+            return result;
+        }
+    }
+
+    private static class BooleanArrayValueGetter extends SimpleAnnotationValueVisitor6<List<Boolean>, Object> {
+
+        @Override
+        public List<Boolean> visitArray(List<? extends AnnotationValue> list, Object p) {
+            List<Boolean> result = new ArrayList<Boolean>();
+            for (AnnotationValue av : list) {
+                result.add(av.accept(new BooleanValueGetter(), null));
+            }
+            return result;
+        }
+    }
+
+    private static class ClassValueGetter extends SimpleAnnotationValueVisitor6<TypeMirror, Object> {
+
+        @Override
+        public TypeMirror visitType(TypeMirror tm, Object p) {
+            return tm;
+        }
+    }
+
+    private static class StringValueGetter extends SimpleAnnotationValueVisitor6<String, Object> {
+
+        @Override
+        public String visitString(String tm, Object p) {
+            return tm;
+        }
+    }
+
+    private static class BooleanValueGetter extends SimpleAnnotationValueVisitor6<Boolean, Object> {
+
+        @Override
+        public Boolean visitBoolean(boolean b, Object p) {
+            return b;
+        }
+    }
+
+    private static class StringTypeGetter extends SimpleTypeVisitor6<String, Object> {
+
+        private final boolean dollar;
+
+        public StringTypeGetter(boolean dollar) {
+            this.dollar = dollar;
+        }
+
+        @Override
+        public String visitDeclared(DeclaredType dt, Object p) {
+            System.out.println("");
+            ElementKind kind = ((TypeElement) dt.asElement()).getEnclosingElement().getKind();
+            if(dollar && (kind == ElementKind.CLASS || kind == ElementKind.INTERFACE)) {
+                return ((TypeElement)(((TypeElement) dt.asElement()).getEnclosingElement())).getQualifiedName().toString() +
+                        "$" + ((TypeElement) dt.asElement()).getSimpleName().toString();
+            } else {
+                return ((TypeElement) dt.asElement()).getQualifiedName().toString();
+            }
+        }
+
+        @Override
+        public String visitPrimitive(PrimitiveType pt, Object p) {
+            return pt.toString();
+        }
+
+        @Override
+        public String visitArray(ArrayType at, Object p) {
+            return at.getComponentType().accept(this, p) + "[]";
+        }
+
+        @Override
+        public String visitTypeVariable(TypeVariable tv, Object p) {
+            return tv.getUpperBound().accept(this, p);
+        }
+
+        @Override
+        public String visitExecutable(ExecutableType et, Object p) {
+            return et.getReturnType().accept(this, p);
+        }
+
+        @Override
+        public String visitNoType(NoType notype, Object p) {
+            return "void";
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/src/org/jemmy/support/SupportParameter.java	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.jemmy.support;
+
+import javax.lang.model.type.TypeMirror;
+
+/**
+ *
+ * @author shura
+ */
+public class SupportParameter {
+    private final TypeMirror type;
+    private final String name;
+
+    /**
+     *
+     * @param name
+     * @param type
+     */
+    public SupportParameter(String name, TypeMirror type) {
+        this.type = type;
+        this.name = name;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     *
+     * @return
+     */
+    public TypeMirror getType() {
+        return type;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/src/org/jemmy/support/Version.java	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.jemmy.support;
+
+/**
+ *
+ * @author shura
+ */
+public class Version extends org.jemmy.Version {
+    /**
+     *
+     */
+    public static final Version VERSION = new Version();
+
+    /**
+     *
+     */
+    public Version() {
+        super();
+    }
+
+    /**
+     *
+     * @param args
+     */
+    public static void main(String[] args) {
+        System.out.println("JemmySupport version: " + VERSION.getVersion() + "." + VERSION.getBuild());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/src/org/jemmy/support/jemmy.properties	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,3 @@
+version.major=0
+version.minor=9
+version.mini=5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/src/org/jemmy/support/package.html.html	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,21 @@
+<!--
+To change this template, choose Tools | Templates
+and open the template in the editor.
+-->
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Jemmy support</title>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+    </head>
+    <body>
+        <h1>Jemmy support</h1>
+        This is an utility code which is responsible for generating Jemmy different
+        artifacts describing now well Jemmy covers this or that UI library.
+        In particular, Jemmy "docks" could be generated. See "Docks vs wraps" 
+        article and examples of wraps for a particular UI library for more info<br/>
+        The required information is collected from annotations within Jemmy code
+        by an "annotation processor" which is implemented by 
+        <code><a href="Proccessor.html">Processor</a></code> class.
+    </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/test/org/jemmy/support/DockTest.java	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.jemmy.support;
+
+import com.company.test.CollectionDock;
+import com.company.test.CollectionRoot;
+import com.company.test.ListDock;
+import com.company.test.ObjectDock;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.util.List;
+import java.util.Set;
+
+import static com.company.test.CollectionRoot.PARENT;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class DockTest {
+    @BeforeClass
+    public static void init() {
+        CollectionRoot.COLLECTIONS.add(List.of(0, 1, 2));
+        CollectionRoot.COLLECTIONS.add(List.of(3, 4, 5, 6));
+        CollectionRoot.COLLECTIONS.add(List.of());
+        CollectionRoot.COLLECTIONS.add(Set.of(0, 1, 2, 3));
+        CollectionRoot.COLLECTIONS.add(Set.of("0", "1", "2"));
+    }
+    @Test
+    public void testCollectionDock() {
+        new CollectionDock(PARENT);
+        new CollectionDock(PARENT, 3);
+        assertTrue(new CollectionDock(PARENT, List.class).control() instanceof List);
+        assertTrue(new CollectionDock(PARENT, Set.class, 1).control() instanceof Set);
+        assertEquals(new CollectionDock(PARENT, List.class, collection -> collection.size() == 4)
+                .getSize(), 4);
+        assertTrue(new CollectionDock(PARENT, List.class, collection -> collection.size() == 0)
+                .isEmpty());
+        assertTrue(new CollectionDock(PARENT, c -> c.size() > 0 && c.iterator().next() instanceof String)
+                .control() instanceof Set);
+    }
+    @Test
+    public void testListDock() {
+        assertEquals(new ListDock(PARENT, collection -> collection.size() == 4)
+                .getSize(), 4);
+        assertEquals(new ListDock(PARENT, collection -> collection.size() == 4)
+                .getIterator().next(), 3);
+    }
+    @Test
+    public void testObjectDock() {
+        ListDock cd = new ListDock(PARENT, c -> c.size() > 3);
+        ObjectDock od = new ObjectDock(cd.asParent(), i -> (Integer)i > 5);
+        assertEquals(od.control(), 6);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/test_data/com/company/test/CollectionRoot.java	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.company.test;
+
+import org.jemmy.control.Wrap;
+import org.jemmy.control.Wrapper;
+import org.jemmy.env.Environment;
+import org.jemmy.interfaces.Parent;
+import org.jemmy.lookup.ControlList;
+import org.jemmy.lookup.ParentImpl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public class CollectionRoot {
+    public static final List<Collection> COLLECTIONS = new ArrayList<>();
+    public static final Parent<Collection> PARENT = new ParentImpl<Collection>(Environment.getEnvironment(),
+            Collection.class, new CollectionList(),
+            new CollectionWrapper());
+
+
+    private static class CollectionList implements ControlList {
+        @Override
+        public List<Collection> getControls() {
+            return COLLECTIONS;
+        }
+    }
+
+    private static class CollectionWrapper implements Wrapper {
+        @Override
+        public <T> Wrap<? extends T> wrap(Class<T> controlClass, T control) {
+            if(control instanceof List) {
+                return new ListWrap(Environment.getEnvironment(), (List)control);
+            } else {
+                return new CollectionWrap(Environment.getEnvironment(), (Collection)control);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/test_data/com/company/test/CollectionWrap.java	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.company.test;
+import org.jemmy.Rectangle;
+import org.jemmy.control.ControlInterfaces;
+import org.jemmy.control.ControlType;
+import org.jemmy.control.MethodProperties;
+import org.jemmy.control.Wrap;
+import org.jemmy.control.Wrapper;
+import org.jemmy.dock.DefaultParent;
+import org.jemmy.dock.DockInfo;
+import org.jemmy.env.Environment;
+import org.jemmy.interfaces.ControlInterface;
+import org.jemmy.interfaces.Parent;
+import org.jemmy.interfaces.TypeControlInterface;
+import org.jemmy.lookup.ControlList;
+import org.jemmy.lookup.ParentImpl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+@ControlType(Collection.class)
+@MethodProperties({"isEmpty", "size"})
+@ControlInterfaces({Parent.class})
+@DockInfo(generateSubtypeLookups = true)
+public class CollectionWrap<T extends Collection> extends Wrap<T> {
+
+    @DefaultParent("collections")
+    public static <C extends Collection> Parent<? super Collection> getRoot(Class<C> cType) {
+        return CollectionRoot.PARENT;
+    }
+
+    private final Parent<Object> parent;
+
+    protected CollectionWrap(Environment env, T node) {
+        super(env, node);
+        parent = new ParentImpl<>(env, Object.class, new ControlList() {
+            @Override
+            public List<?> getControls() {
+                return new ArrayList<>(getControl());
+            }
+        }, new Wrapper() {
+            @Override
+            public <T> Wrap<? extends T> wrap(Class<T> controlClass, T control) {
+                return (Wrap<T>)new ObjectWrap<T>(getEnvironment(), control);
+            }
+        });
+    }
+
+    @Override
+    public Rectangle getScreenBounds() {
+        return new Rectangle();
+    }
+
+    @Override
+    public <INTERFACE extends ControlInterface> boolean is(Class<INTERFACE> aClass) {
+        if(Parent.class.isAssignableFrom(aClass)) {
+            return true;
+        }
+        return super.is(aClass);
+    }
+
+    @Override
+    public <INTERFACE extends ControlInterface> INTERFACE as(Class<INTERFACE> aClass) {
+        if(Parent.class.isAssignableFrom(aClass)) {
+            return (INTERFACE) parent;
+        }
+        return super.as(aClass);
+    }
+
+    @Override
+    public <TYPE, INTERFACE extends TypeControlInterface<TYPE>> boolean is(Class<INTERFACE> aClass, Class<TYPE> type) {
+        if(Parent.class.isAssignableFrom(aClass) && type.equals(Object.class)) {
+            return true;
+        }
+        return super.is(aClass, type);
+    }
+
+    @Override
+    public <TYPE, INTERFACE extends TypeControlInterface<TYPE>> INTERFACE as(Class<INTERFACE> aClass, Class<TYPE> type) {
+        if(Parent.class.isAssignableFrom(aClass) && type.equals(Object.class)) {
+            return (INTERFACE) parent;
+        }
+        return super.as(aClass, type);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/test_data/com/company/test/ListWrap.java	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.company.test;
+
+import org.jemmy.control.ControlInterfaces;
+import org.jemmy.control.ControlType;
+import org.jemmy.control.MethodProperties;
+import org.jemmy.dock.DefaultParent;
+import org.jemmy.dock.DockInfo;
+import org.jemmy.dock.PreferredParent;
+import org.jemmy.dock.Shortcut;
+import org.jemmy.env.Environment;
+import org.jemmy.interfaces.Parent;
+import org.jemmy.interfaces.Selectable;
+import org.jemmy.interfaces.Selector;
+
+import java.util.Collection;
+import java.util.List;
+
+@ControlType(List.class)
+@DockInfo
+@MethodProperties({"iterator"})
+@ControlInterfaces({Selectable.class})
+@PreferredParent(CollectionWrap.class)
+public class ListWrap<T extends List> extends CollectionWrap<T> implements Selectable<Object> {
+
+    @DefaultParent("collections")
+    public static <C extends Collection> Parent<? super Collection> getRoot(Class<C> cType) {
+        return CollectionRoot.PARENT;
+    }
+
+    protected ListWrap(Environment env, T node) {
+        super(env, node);
+    }
+
+    @Override
+    public List<Object> getStates() {
+        return getControl();
+    }
+
+    private volatile Object state = null;
+
+    @Override
+    @Shortcut
+    public Object getState() {
+        return state;
+    }
+
+    @Override
+    @Shortcut
+    public Selector<Object> selector() {
+        return new Selector<Object>() {
+            @Override
+            public void select(Object o) {
+                if(getControl().contains(o))
+                    state = o;
+                else
+                    throw new IllegalStateException(o + "is not contained");
+            }
+        };
+    }
+
+    @Override
+    public Class<Object> getType() {
+        return Object.class;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmySupport/test_data/com/company/test/ObjectWrap.java	Tue Jan 08 15:44:49 2019 -0800
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.company.test;
+
+import org.jemmy.Rectangle;
+import org.jemmy.control.ControlType;
+import org.jemmy.control.Wrap;
+import org.jemmy.dock.DockInfo;
+import org.jemmy.env.Environment;
+
+@ControlType(Object.class)
+@DockInfo(generateSubtypeLookups = true)
+public class ObjectWrap<T> extends Wrap<T> {
+    protected ObjectWrap(Environment env, T node) {
+        super(env, node);
+    }
+
+    @Override
+    public Rectangle getScreenBounds() {
+        return new Rectangle();
+    }
+}
--- a/core/make/jemmy-v3-ii/.idea/misc.xml	Mon Jun 18 10:38:21 2018 +0300
+++ b/core/make/jemmy-v3-ii/.idea/misc.xml	Tue Jan 08 15:44:49 2019 -0800
@@ -1,6 +1,32 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
-  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_9" default="true" project-jdk-name="1.9" project-jdk-type="JavaSDK">
+  <component name="MavenBuildProjectComponent">
+    <option name="mavenExecutable" value="" />
+    <option name="Settings File" value="$USER_HOME$/.m2/settings.xml" />
+    <option name="mavenCommandLineParams" value="" />
+    <option name="vmOptions" value="" />
+    <option name="useMavenEmbedder" value="false" />
+    <option name="useFilter" value="false" />
+    <option name="Batch Mode" value="false" />
+    <option name="Check Plugin Updates" value="false" />
+    <option name="Debug" value="false" />
+    <option name="Errors" value="false" />
+    <option name="Fail At End" value="false" />
+    <option name="Fail Fast" value="false" />
+    <option name="Fail Never" value="false" />
+    <option name="Lax Checksums" value="false" />
+    <option name="No Plugin Registry" value="false" />
+    <option name="No Plugin Updates" value="false" />
+    <option name="Non Recursive" value="false" />
+    <option name="Offline" value="false" />
+    <option name="Reactor" value="false" />
+    <option name="Strict Checksums" value="false" />
+    <option name="Update Plugins" value="false" />
+    <option name="Update Snapshots" value="false" />
+    <option name="Skip Tests" value="false" />
+    <pom-list />
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
     <output url="file://$PROJECT_DIR$/out" />
   </component>
-</project>
+</project>
\ No newline at end of file
--- a/core/make/jemmy-v3-ii/.idea/modules.xml	Mon Jun 18 10:38:21 2018 +0300
+++ b/core/make/jemmy-v3-ii/.idea/modules.xml	Tue Jan 08 15:44:49 2019 -0800
@@ -5,6 +5,7 @@
       <module fileurl="file://$PROJECT_DIR$/awt-input/awt-input.iml" filepath="$PROJECT_DIR$/awt-input/awt-input.iml" />
       <module fileurl="file://$PROJECT_DIR$/browser/browser.iml" filepath="$PROJECT_DIR$/browser/browser.iml" />
       <module fileurl="file://$PROJECT_DIR$/core/core.iml" filepath="$PROJECT_DIR$/core/core.iml" />
+      <module fileurl="file://$PROJECT_DIR$/support/support.iml" filepath="$PROJECT_DIR$/support/support.iml" />
     </modules>
   </component>
-</project>
+</project>
\ No newline at end of file
--- a/make/build_template.xml	Mon Jun 18 10:38:21 2018 +0300
+++ b/make/build_template.xml	Tue Jan 08 15:44:49 2019 -0800
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
- Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
  This code is free software; you can redistribute it and/or modify it
@@ -49,11 +49,11 @@
         <copy file="${src.dir}/${version.file}" tofile="${build.classes.dir}/${version.file}"/>
         <replaceregexp file="${build.classes.dir}/${version.file}" match="\$\{buildnumber\}" replace="${buildnumber}" byline="true"/>
     </target>
-    <target name="compile-test" depends="compile">
+    <target name="compile-test" depends="compile,build-test-dependencies">
         <fail message="Please specify jtreg.home" unless="jtreg.home"/>
         <mkdir dir="${build.test.dir}"/>
         <javac srcdir="${test.dir}" destdir="${build.test.dir}" debug="on" includeantruntime="false"
-               classpath="${build.classes.dir}:${dependencies.classpath}:${jtreg.home}/lib/testng.jar"/>
+               classpath="${build.classes.dir}:${dependencies.classpath}:${test.dependencies.classpath}:${jtreg.home}/lib/testng.jar"/>
     </target>
     <target name="find-tests" unless="tests">
         <fileset id="testset" dir="${test.dir}">
@@ -65,7 +65,10 @@
         <echo file="${test.list}">${testlist}</echo>
         <property name="tests" value="@${test.list}"/>
     </target>
-    <target name="test" depends="compile-test,find-tests">
+    <target name="build-test-dependencies" if="test.dependencies.classpath">
+        <antcall target="build-test-dependecies-impl"/>
+    </target>
+    <target name="test" depends="build-test-dependencies,compile-test,find-tests">
         <exec executable="${jtreg.home}/bin/jtreg">
             <arg value="-cpa:${build.classes.dir}:${dependencies.classpath}"/>
             <arg value="-w:${test.workdir}"/>