更新时间:2022-09-11 10:09:01
源代码如下:
package com.sap.crm.ui.core.pages; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.sap.crm.ui.core.tags.ContainerElement; import com.sap.crm.ui.core.tags.Element; import com.sap.crm.ui.core.tags.ElementFactory; import com.sap.crm.ui.core.tags.ParentElement; import com.sap.crm.ui.core.tags.SubFactory; import com.sap.crm.ui.core.tags.UISession; public class AbstractPage { protected final UISession session; protected ParentElement container; public AbstractPage(final UISession session) { super(); this.session = session; init(); } protected void init() { final List<Field> fields = new ArrayList<Field>(); final List<Field> subFields = new ArrayList<Field>(); Map<Class<? extends SubObject>, Map<String, SubFactory<? extends SubObject>>> subFactories = new HashMap<>(); Page pageAnnotation = this.getClass().getAnnotation(Page.class); Location defaultLocation = null; if (pageAnnotation != null) { defaultLocation = pageAnnotation.defaultLocation(); } // Retrieve all fields/members that are declared as // public/protected/private. for (final Field field : this.getClass().getDeclaredFields()) { if (!field.isAccessible()) field.setAccessible(true); final Class<?> type = field.getType(); if (Element.class.isAssignableFrom(type) || type == String.class) { if (field.getAnnotation(Container.class) != null) { fields.add(0, field); } else { fields.add(field); } } else if (AbstractPage.class.isAssignableFrom(type)) { // element is inheriting from AbstractPage createSubPage(field, type); } else if (SubObject.class.isAssignableFrom(type)) { // subFactory e.g. for table columns subFields.add(field); } } // Now consider all fields that have a PageElement annotation and create // the concrete element instances via factory for (final Field field : fields) { PageElement pageElement = resolveAnnotations(field); if (pageElement != null) { final Class<?> type = field.getType(); if (type == String.class) { // Just a versioned ID setField(field, pageElement.id()); continue; } // Determine element type @SuppressWarnings("unchecked") Class<? extends Element> fieldType = (Class<? extends Element>) type; if (pageElement.type() != Element.class) { if (!fieldType.isAssignableFrom(pageElement.type())) { throw new IllegalArgumentException(); } fieldType = pageElement.type(); } // Get factory dependent from location Element element; ElementFactory factory = null; factory = resolveLocation(factory, pageElement, defaultLocation); // Check if proxy needed if (ElementFactory.isConcreteType(fieldType)) { // Concrete type is known, no proxy needed element = factory.element(fieldType, pageElement.id()); } else { // Final Type is not known, need a proxy element = factory.proxy(pageElement.id()); } if (field.getAnnotation(Container.class) != null) { container = (ContainerElement) element; } setField(field, element); // Remember subFactories if (SubFactory.class.isAssignableFrom(fieldType)) { registerSubFactory(subFactories, field, fieldType, element); } } } // Instantiate subObject fields from factories for (Field subField : subFields) { PageElement pageElement = resolveAnnotations(subField); // Get factory Map<String, SubFactory<? extends SubObject>> subFactoriesForType = subFactories .get(subField.getType()); if (subFactoriesForType == null) { throw new IllegalArgumentException("Subfactory for type " + subField.getType() + " could not be found on page"); } SubFactory<? extends SubObject> subFactory = subFactoriesForType .get(pageElement.subFactoryName()); if (subFactory == null) { throw new IllegalArgumentException("Subfactory for type " + subField.getType() + " with name " + pageElement.subFactoryName() + " could not be found on page"); } // Get parametrization for generic types ParameterizedType genericType = (ParameterizedType) subField .getGenericType(); Type[] actualTypeArguments = genericType.getActualTypeArguments(); // Produce and assign Object subObject = subFactory.produce(pageElement.id(), actualTypeArguments); try { subField.set(this, subObject); } catch (final IllegalAccessException e) { throw new IllegalStateException(e); } } } private void setField(final Field field, Object value) { try { field.set(this, value); } catch (final IllegalAccessException e) { throw new IllegalStateException(e); } } private void createSubPage(final Field field, final Class<?> type) { @SuppressWarnings("unchecked") final Class<? extends AbstractPage> pageType = (Class<AbstractPage>) type; // Create sub pages try { final Constructor<? extends AbstractPage> constructor = pageType .getConstructor(UISession.class); try { final AbstractPage page = constructor.newInstance(session); field.set(this, page); } catch (final IllegalArgumentException e) { e.printStackTrace(); } catch (final InstantiationException e) { e.printStackTrace(); } catch (final IllegalAccessException e) { e.printStackTrace(); } catch (final InvocationTargetException e) { e.printStackTrace(); } } catch (final NoSuchMethodException e) { // Ignore it, has to be coded manually } } private ElementFactory resolveLocation(ElementFactory factory, PageElement pageElement, Location defaultLocation) { Location location = pageElement.location(); if (location == Location.DEFAULT && defaultLocation != null) { location = defaultLocation; } switch (location) { case ROOT: factory = session.ui(); break; case CONTAINER: factory = container.contained(); break; case DEFAULT: if (container != null) { factory = container.contained(); } else { factory = session.workArea(); } break; case TOOLBAR: factory = session.getToolbarFactory(); break; case WORK_AREA: factory = session.workArea(); break; } return factory; } private void registerSubFactory( Map<Class<? extends SubObject>, Map<String, SubFactory<? extends SubObject>>> subFactories, final Field field, Class<? extends Element> fieldType, Element element) { @SuppressWarnings("unchecked") SubFactory<? extends SubObject> subFactory = (SubFactory<? extends SubObject>) element; // Determine Name com.sap.crm.ui.core.pages.SubFactory annotation = field .getAnnotation(com.sap.crm.ui.core.pages.SubFactory.class); String subFactoryName = (annotation != null) ? annotation.name() : ""; Class<? extends SubObject> targetType = findSubObjectFactoryTargetType(fieldType); Map<String, SubFactory<? extends SubObject>> subFactoriesForType = subFactories .get(targetType); if (subFactoriesForType == null) { subFactoriesForType = new HashMap<>(); subFactories.put(targetType, subFactoriesForType); } if (subFactoriesForType.put(subFactoryName, subFactory) != null) { throw new IllegalStateException( "Ambiguous subObjectFactories on page for type " + targetType + " with name " + subFactoryName); } } @SuppressWarnings("unchecked") private Class<? extends SubObject> findSubObjectFactoryTargetType( Class<? extends Element> fieldType) { Type[] genericInterfaces = fieldType.getGenericInterfaces(); for (Type intf : genericInterfaces) { if (intf instanceof ParameterizedType && ((ParameterizedType) intf).getRawType() == SubFactory.class) { Type[] actualTypeArguments = ((ParameterizedType) intf) .getActualTypeArguments(); Type type = actualTypeArguments[0]; Class<? extends SubObject> targetType; if (type instanceof ParameterizedType) { targetType = (Class<? extends SubObject>) ((ParameterizedType) type) .getRawType(); } else { targetType = (Class<? extends SubObject>) type; } return targetType; } } throw new IllegalArgumentException(); } private PageElement resolveAnnotations(final Field field) { // Fetch annotations final Versioned versionedAnnotation = field .getAnnotation(Versioned.class); PageElement pageElement = field.getAnnotation(PageElement.class); // Process versions if (versionedAnnotation != null) { int highestVersion = 0; for (final Version version : versionedAnnotation.versions()) { if (version.majorVersion() >= session.getMajorVersion() && version.majorVersion() > highestVersion) { pageElement = version.element(); highestVersion = version.majorVersion(); } } } return pageElement; } }