private QueryMetadata projection(Expression<?>... projection) {
   QueryMetadata metadata = queryMixin.getMetadata().clone();
   for (Expression<?> expr : projection) {
     metadata.addProjection(nullAsTemplate(expr));
   }
   return metadata;
 }
 private QueryMetadata projection(
     Expression<?> first, Expression<?> second, Expression<?>[] rest) {
   QueryMetadata metadata = queryMixin.getMetadata().clone();
   metadata.addProjection(nullAsTemplate(first));
   metadata.addProjection(nullAsTemplate(second));
   for (Expression<?> expr : rest) {
     metadata.addProjection(nullAsTemplate(expr));
   }
   return metadata;
 }
  @Override
  public void serialize(QueryMetadata metadata, boolean forCountRow, SQLSerializer context) {
    if (!forCountRow && metadata.getModifiers().isRestricting() && !metadata.getJoins().isEmpty()) {
      QueryModifiers mod = metadata.getModifiers();
      if (mod.getOffset() == null) {
        // select top ...
        metadata = metadata.clone();
        metadata.addFlag(
            new QueryFlag(
                QueryFlag.Position.AFTER_SELECT,
                Expressions.template(Integer.class, topTemplate, mod.getLimit())));
        context.serializeForQuery(metadata, forCountRow);
      } else {
        throw new IllegalStateException("offset not supported");
      }

    } else {
      context.serializeForQuery(metadata, forCountRow);
    }

    if (!metadata.getFlags().isEmpty()) {
      context.serialize(Position.END, metadata.getFlags());
    }
  }
  @Test
  public void test() throws IOException, ClassNotFoundException {
    // create query
    JPAQuery query = new JPAQuery(entityManager);
    query.from(cat).where(cat.name.eq("Kate")).list(cat);

    // get metadata
    QueryMetadata metadata = query.getMetadata();
    assertFalse(metadata.getJoins().isEmpty());
    assertTrue(metadata.getWhere() != null);
    assertTrue(metadata.getProjection().isEmpty());

    // serialize metadata
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream out = new ObjectOutputStream(baos);
    out.writeObject(metadata);
    out.close();

    // deserialize metadata
    ByteArrayInputStream bain = new ByteArrayInputStream(baos.toByteArray());
    ObjectInputStream in = new ObjectInputStream(bain);
    QueryMetadata metadata2 = (QueryMetadata) in.readObject();
    in.close();

    // validate it
    assertEquals(metadata.getJoins(), metadata2.getJoins());
    assertEquals(metadata.getWhere(), metadata2.getWhere());
    assertEquals(metadata.getProjection(), metadata2.getProjection());

    // create new query
    JPAQuery query2 = new JPAQuery(entityManager, metadata2);
    assertEquals("from Cat cat\nwhere cat.name = :a1", query2.toString());
    query2.list(cat);
  }
 private QueryMetadata uniqueProjection(
     Expression<?> first, Expression<?> second, Expression<?>[] rest) {
   QueryMetadata metadata = projection(first, second, rest);
   metadata.setUnique(true);
   return metadata;
 }
 private QueryMetadata uniqueProjection(Expression<?>... projection) {
   QueryMetadata metadata = projection(projection);
   metadata.setUnique(true);
   return metadata;
 }