private void serialize(Serializer serializer, Collection<EntityType> models) {
    for (EntityType model : models) {
      try {
        Type type = conf.getTypeMappings().getPathType(model, model, true);
        String packageName = type.getPackageName();
        String className =
            !packageName.isEmpty()
                ? (packageName + "." + type.getSimpleName())
                : type.getSimpleName();

        // skip if type is excluded class or in excluded package
        if (conf.isExcludedPackage(model.getPackageName())
            || conf.isExcludedClass(model.getFullName())) {
          continue;
        }

        Set<TypeElement> elements = context.typeElements.get(model.getFullName());

        if (elements == null) {
          elements = new HashSet<TypeElement>();
        }
        for (Property property : model.getProperties()) {
          if (property.getType().getCategory() == TypeCategory.CUSTOM) {
            Set<TypeElement> customElements =
                context.typeElements.get(property.getType().getFullName());
            if (customElements != null) {
              elements.addAll(customElements);
            }
          }
        }

        processingEnv
            .getMessager()
            .printMessage(Kind.NOTE, "Generating " + className + " for " + elements);
        JavaFileObject fileObject =
            processingEnv
                .getFiler()
                .createSourceFile(className, elements.toArray(new Element[elements.size()]));
        Writer writer = fileObject.openWriter();
        try {
          SerializerConfig serializerConfig = conf.getSerializerConfig(model);
          serializer.serialize(model, serializerConfig, new JavaWriter(writer));
        } finally {
          if (writer != null) {
            writer.close();
          }
        }

      } catch (IOException e) {
        System.err.println(e.getMessage());
        processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage());
      }
    }
  }
 private void processProjectionTypes(Set<TypeElement> elements) {
   Set<Element> visited = new HashSet<Element>();
   for (Element element : getElements(QueryProjection.class)) {
     Element parent = element.getEnclosingElement();
     if (!elements.contains(parent) && !visited.contains(parent)) {
       EntityType model = elementHandler.handleProjectionType((TypeElement) parent);
       registerTypeElement(model.getFullName(), (TypeElement) parent);
       context.projectionTypes.put(model.getFullName(), model);
       visited.add(parent);
     }
   }
 }
 private void addSupertypeFields(EntityType model, Set<EntityType> handled) {
   if (handled.add(model)) {
     for (Supertype supertype : model.getSuperTypes()) {
       EntityType entityType = context.allTypes.get(supertype.getType().getFullName());
       if (entityType != null) {
         addSupertypeFields(entityType, handled);
         supertype.setEntityType(entityType);
         model.include(supertype);
       }
     }
   }
 }
 private EntityType createEntityType(Class<?> cl, Map<String, EntityType> types) {
   if (types.containsKey(cl.getName())) {
     return types.get(cl.getName());
   } else {
     EntityType type = new EntityType(new ClassType(TypeCategory.ENTITY, cl));
     typeMappings.register(type, queryTypeFactory.create(type));
     if (!cl.getSuperclass().equals(Object.class)) {
       type.addSupertype(new Supertype(new ClassType(cl.getSuperclass())));
     }
     types.put(cl.getName(), type);
     allTypes.put(cl.getName(), type);
     return type;
   }
 }
 private void validateMetaTypes() {
   for (Collection<EntityType> entityTypes :
       Arrays.asList(
           context.supertypes.values(),
           context.entityTypes.values(),
           context.extensionTypes.values(),
           context.embeddableTypes.values(),
           context.projectionTypes.values())) {
     for (EntityType entityType : entityTypes) {
       for (Property property : entityType.getProperties()) {
         if (property.getInits() != null && property.getInits().size() > 0) {
           validateInits(entityType, property);
         }
       }
     }
   }
 }
 private void addExternalParents(EntityType entityType) {
   Deque<Type> superTypes = new ArrayDeque<Type>();
   if (entityType.getSuperType() != null) {
     superTypes.push(entityType.getSuperType().getType());
   }
   while (!superTypes.isEmpty()) {
     Type superType = superTypes.pop();
     if (!context.allTypes.containsKey(superType.getFullName())) {
       TypeElement typeElement =
           processingEnv.getElementUtils().getTypeElement(superType.getFullName());
       if (typeElement == null) {
         throw new IllegalStateException("Found no type for " + superType.getFullName());
       }
       EntityType superEntityType = elementHandler.handleEntityType(typeElement);
       if (entityType.getSuperType() != null) {
         superTypes.push(entityType.getSuperType().getType());
       }
       context.allTypes.put(superType.getFullName(), superEntityType);
     }
   }
 }
  private void collectTypes()
      throws IOException, XMLStreamException, ClassNotFoundException, SecurityException,
          NoSuchMethodException {
    // super classes
    Iterator<?> superClassMappings = configuration.getMappedSuperclassMappings();
    while (superClassMappings.hasNext()) {
      MappedSuperclass msc = (MappedSuperclass) superClassMappings.next();
      EntityType entityType = createSuperType(msc.getMappedClass());
      if (msc.getDeclaredIdentifierProperty() != null) {
        handleProperty(entityType, msc.getMappedClass(), msc.getDeclaredIdentifierProperty());
      }
      Iterator<?> properties = msc.getDeclaredPropertyIterator();
      while (properties.hasNext()) {
        handleProperty(
            entityType, msc.getMappedClass(), (org.hibernate.mapping.Property) properties.next());
      }
    }

    // entity classes
    Iterator<?> classMappings = configuration.getClassMappings();
    while (classMappings.hasNext()) {
      PersistentClass pc = (PersistentClass) classMappings.next();
      EntityType entityType = createEntityType(pc.getMappedClass());
      if (pc.getDeclaredIdentifierProperty() != null) {
        handleProperty(entityType, pc.getMappedClass(), pc.getDeclaredIdentifierProperty());
      } else if (!pc.isInherited() && pc.hasIdentifierProperty()) {
        logger.info(entityType.toString() + pc.getIdentifierProperty());
        handleProperty(entityType, pc.getMappedClass(), pc.getIdentifierProperty());
      }
      Iterator<?> properties = pc.getDeclaredPropertyIterator();
      while (properties.hasNext()) {
        handleProperty(
            entityType, pc.getMappedClass(), (org.hibernate.mapping.Property) properties.next());
      }
    }
  }
  private Set<TypeElement> processDelegateMethods() {
    Set<Element> delegateMethods = (Set) getElements(QueryDelegate.class);
    Set<TypeElement> typeElements = new HashSet<TypeElement>();

    for (Element delegateMethod : delegateMethods) {
      ExecutableElement method = (ExecutableElement) delegateMethod;
      Element element = delegateMethod.getEnclosingElement();
      String name = method.getSimpleName().toString();
      Type delegateType = typeFactory.getType(element.asType(), true);
      Type returnType = typeFactory.getType(method.getReturnType(), true);
      List<Parameter> parameters = elementHandler.transformParams(method.getParameters());
      // remove first element
      parameters = parameters.subList(1, parameters.size());

      EntityType entityType = null;
      for (AnnotationMirror annotation : delegateMethod.getAnnotationMirrors()) {
        if (TypeUtils.isAnnotationMirrorOfType(annotation, QueryDelegate.class)) {
          TypeMirror type = TypeUtils.getAnnotationValueAsTypeMirror(annotation, "value");
          if (type != null) {
            entityType = typeFactory.getEntityType(type, true);
          }
        }
      }

      if (entityType != null) {
        registerTypeElement(entityType.getFullName(), (TypeElement) element);
        entityType.addDelegate(
            new Delegate(entityType, delegateType, name, parameters, returnType));
        TypeElement typeElement =
            processingEnv.getElementUtils().getTypeElement(entityType.getFullName());
        boolean isAnnotated = false;
        for (Class<? extends Annotation> ann : conf.getEntityAnnotations()) {
          if (typeElement.getAnnotation(ann) != null) {
            isAnnotated = true;
          }
        }
        if (isAnnotated) {
          // handle also properties of entity type
          typeElements.add(
              processingEnv.getElementUtils().getTypeElement(entityType.getFullName()));
        } else {
          // skip handling properties
          context.extensionTypes.put(entityType.getFullName(), entityType);
          context.allTypes.put(entityType.getFullName(), entityType);
        }
      }
    }

    return typeElements;
  }
 private void handleProperty(EntityType entityType, Class<?> cl, org.hibernate.mapping.Property p)
     throws NoSuchMethodException, ClassNotFoundException {
   Type propertyType = getType(cl, p.getName());
   if (p.isComposite()) {
     Class<?> embeddedClass = Class.forName(propertyType.getFullName());
     EntityType embeddedType = createEmbeddableType(embeddedClass);
     Iterator<?> properties = ((Component) p.getValue()).getPropertyIterator();
     while (properties.hasNext()) {
       handleProperty(
           embeddedType, embeddedClass, (org.hibernate.mapping.Property) properties.next());
     }
     propertyType = embeddedType;
   } else if (propertyType.getCategory() == TypeCategory.ENTITY) {
     propertyType = createEntityType(Class.forName(propertyType.getFullName()));
   }
   AnnotatedElement annotated = getAnnotatedElement(cl, p.getName());
   Property property = createProperty(entityType, p.getName(), propertyType, annotated);
   entityType.addProperty(property);
 }
 protected void validateInits(EntityType entityType, Property property) {
   for (String init : property.getInits()) {
     if (!init.startsWith("*") && property.getType() instanceof EntityType) {
       String initProperty = init.contains(".") ? init.substring(0, init.indexOf('.')) : init;
       if (!((EntityType) property.getType()).getPropertyNames().contains(initProperty)) {
         processingEnv
             .getMessager()
             .printMessage(
                 Kind.ERROR,
                 "Illegal inits of "
                     + entityType.getFullName()
                     + "."
                     + property.getName()
                     + ": "
                     + initProperty
                     + " not found");
       }
     }
   }
 }
  private void processAnnotations() {
    processExclusions();

    Set<TypeElement> elements = collectElements();

    // create meta models
    for (Element element : elements) {
      typeFactory.getEntityType(element.asType(), false);
    }
    for (Element element : elements) {
      typeFactory.getEntityType(element.asType(), true);
    }

    // add properties
    boolean embeddableAnn = conf.getEmbeddableAnnotation() != null;
    boolean altEntityAnn = conf.getAlternativeEntityAnnotation() != null;
    boolean superAnn = conf.getSuperTypeAnnotation() != null;
    for (TypeElement element : elements) {
      EntityType entityType = elementHandler.handleEntityType(element);
      registerTypeElement(entityType.getFullName(), element);
      if (element.getAnnotation(conf.getEntityAnnotation()) != null) {
        context.entityTypes.put(entityType.getFullName(), entityType);
      } else if (altEntityAnn
          && element.getAnnotation(conf.getAlternativeEntityAnnotation()) != null) {
        context.entityTypes.put(entityType.getFullName(), entityType);
      } else if (embeddableAnn && element.getAnnotation(conf.getEmbeddableAnnotation()) != null) {
        context.embeddableTypes.put(entityType.getFullName(), entityType);
      } else if (superAnn && element.getAnnotation(conf.getSuperTypeAnnotation()) != null) {
        context.supertypes.put(entityType.getFullName(), entityType);
      } else if (!entityType.getDelegates().isEmpty()) {
        context.extensionTypes.put(entityType.getFullName(), entityType);
      } else {
        context.embeddableTypes.put(entityType.getFullName(), entityType);
      }
      context.allTypes.put(entityType.getFullName(), entityType);
    }

    // track also methods from external entity types
    for (EntityType entityType : new ArrayList<EntityType>(typeFactory.getEntityTypes())) {
      String fullName = entityType.getFullName();
      if (!context.allTypes.keySet().contains(fullName)) {
        // System.err.println(fullName);
        TypeElement element = processingEnv.getElementUtils().getTypeElement(fullName);
        if (element != null) {
          elementHandler.handleEntityType(element);
        }
      }
    }

    // add external parents
    for (Element element : elements) {
      EntityType entityType = typeFactory.getEntityType(element.asType(), false);
      addExternalParents(entityType);
    }

    // add properties from parents
    Set<EntityType> handled = new HashSet<EntityType>();
    for (EntityType entityType : context.allTypes.values()) {
      addSupertypeFields(entityType, handled);
    }

    processProjectionTypes(elements);

    // extend entity types
    typeFactory.extendTypes();

    context.clean();
  }