@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Accessors(fluent = true, chain = true)
@EqualsAndHashCode(of = {}, callSuper = true)
public class Develops extends Edge {

  /**
   * Go to the {@link Person} who develop the currently selected {@link Software}s.
   */
  public final static ToVertex Developers = traversal -> traversal
      .in(Label.of(Develops.class))
      .hasLabel(Label.of(Person.class));
  public final static ToVertex Softwares = traversal -> traversal
      .out(Label.of(Develops.class))
      .hasLabel(Label.of(Software.class));
  private Instant since;

  public static Develops of(Instant since) {
    return Develops.builder().since(since).build();
  }

  public static Develops of(int year) {
    return of(Location.year(year));
  }

  @Override
  protected List<Connection> connections() {
    return Connection.list(Person.class, Software.class);
  }
} @Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Alias(label = "person")
@Accessors(fluent = true, chain = true)
@EqualsAndHashCode(of = {}, callSuper = true)
public class Person extends Vertex {

  public static ToVertex KnowsPeople = traversal -> traversal
      .out(Label.of(Knows.class))
      .hasLabel(Label.of(Person.class));

  @PrimaryKey
  private String name;

  @OrderingKey
  private int age;

  /**
   * Since the lambda object below is instance-specific, it needs to either have it's name start
   * with a {@code $} symbol, or be marked as {@code transient}. If you have a lot of such
   * instance-specific lambda fields, then you could ignore them all for the purposes of {@link
   * #equals(Object)} and {@link #hashCode()}, by including {@code of={}} in the {@link
   * EqualsAndHashCode} annotation above.
   */
  public final AnyTraversal $sameAge = g -> g.V()
      .hasLabel(Label.of(Knows.class))
      .has("age", age);

  /**
   * This is a multi-property of primitive types.
   */
  private Set<String> titles;

  /**
   * This is a multi-property of a vertex property, each of which has meta-properties of its own.
   */
  private List<Location> locations;

  public static Person of(String name, Location... locations) {
    return of(name, 0, locations);
  }

  public static Person of(String name, int age) {
    return of(name, age, (Location[]) null);
  }

  public static Person of(String name, int age, Location... locations) {
    return of(name, age, null, locations);
  }

  public static Person of(String name, String title, Location... locations) {
    return of(name, 0, title, locations);
  }

  public static Person of(String name, int age, String title, Location... locations) {
    Set<String> titleSet = null;
    if (title != null) {
      titleSet = new HashSet<>();
      Collections.addAll(titleSet, title);
    }
    List<Location> locationList = null;
    if (locations != null && locations.length > 0) {
      locationList = Arrays.asList(locations);
    }
    return of(name, age, titleSet, locationList);
  }

  public static Person of(String name, int age, Set<String> titles, List<Location> locations) {
    Person.PersonBuilder builder = Person.builder().name(name).age(age);
    if (locations != null) {
      builder.locations(locations);
    }
    if (titles != null) {
      builder.titles(titles);
    }
    return builder.build();
  }
} @Data
@ToString
@NoArgsConstructor
@Accessors(fluent = true, chain = true)
@EqualsAndHashCode(callSuper = true, of = {})
public abstract class Edge extends Element {

  /**
   * The object representation of the "from" vertex.
   */
  @Hidden
  private Vertex from;
  /**
   * The object representation of the "to" vertex.
   */
  @Hidden
  private Vertex to;

  /**
   * The id of the "from" vertex.
   */
  @Hidden
  private Object fromId;
  /**
   * The id of the "to" vertex.
   */
  @Hidden
  private Object toId;

  @Hidden
  private List<Connection> cachedConnections;

  protected abstract List<Connection> connections();


  /**
   * Return the underlying gremlin edge.
   */
  public org.apache.tinkerpop.gremlin.structure.Edge delegate() {
    return (org.apache.tinkerpop.gremlin.structure.Edge) delegate;
  }


  /**
   * Return the "from" vertex as the given type.
   */
  public <V extends Vertex> V fromAs(Class<V> vertexType) {
    return Parser.as(from.delegate(), vertexType);
  }

  /**
   * Return the "to" vertex as the given type.
   */
  public <V extends Vertex> V toAs(Class<V> vertexType) {
    return Parser.as(to.delegate(), vertexType);
  }

  /**
   * Does the edge have a connection between the given vertices?
   */
  @SuppressWarnings("PMD.CloseResource")
  public boolean connects(Vertex from, Vertex to) {
    return connects(from.getClass(), to.getClass());
  }

  /**
   * Does the edge have a connection between the given vertex types?
   */
  @SuppressWarnings("PMD.CloseResource")
  public boolean connects(Class<? extends Vertex> fromClass, Class<? extends Vertex> toClass) {
    Connection connection = Connection.of(fromClass, toClass);
    if (cachedConnections == null) {
      cachedConnections = connections();
    }
    return cachedConnections.contains(connection);
  }

  /**
   * A function denoting a {@code GraphTraversal} that starts at edges, and ends at vertices.
   */
  public interface ToVertex extends SubTraversal<
      org.apache.tinkerpop.gremlin.structure.Edge,
      org.apache.tinkerpop.gremlin.structure.Vertex> {

  }

  public static class Exceptions extends Element.Exceptions {

    private Exceptions() {}

    public static IllegalStateException missingEdgeVertex(
        Direction direction, Edge edge, org.apache.tinkerpop.gremlin.structure.Vertex vertex) {
      return missingEdgeVertex(direction, edge, vertex.toString());
    }

    public static IllegalStateException missingEdgeVertex(
        Direction direction, Edge edge, AnyTraversal anyTraversal) {
      return missingEdgeVertex(direction, edge, anyTraversal.toString());
    }

    @SuppressWarnings("rawtypes")
    public static IllegalStateException missingEdgeVertex(
        Direction direction, Edge edge, SubTraversal... subTraversals) {
      return missingEdgeVertex(direction, edge, Arrays.asList(subTraversals).toString());
    }

    public static IllegalStateException missingEdgeVertex(Direction direction, Edge edge,
        String vertexString) {
      return new IllegalStateException(
          String.format("%s vertex (%s) doesn't exist for edge %s",
              direction.equals(Direction.OUT) ? "Outgoing" : "Incoming", vertexString,
              edge));
    }

    public static IllegalStateException invalidEdgeConnection(Edge edge) {
      return new IllegalStateException(
          String.format("Edge connects an invalid pair of vertices", edge));
    }
  }
} @Data
@ToString
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@SuppressWarnings("PMD.CommentSize")
public class Vertex extends Element {

  public Vertex(Element element) {
    super(element);
  }

  /**
   * Return the underlying gremlin vertex.
   */
  public org.apache.tinkerpop.gremlin.structure.Vertex delegate() {
    return (org.apache.tinkerpop.gremlin.structure.Vertex) delegate;
  }

  /**
   * Remove this vertex, if attached.
   */
  public void remove() {
    org.apache.tinkerpop.gremlin.structure.Vertex delegate = delegate();
    if (delegate == null) {
      throw Element.Exceptions.removingDetachedElement(this);
    }
    delegate.remove();
  }

  /**
   * A function denoting a {@code GraphTraversal} that starts at vertices, and ends at vertices.
   */
  public interface ToVertex extends SubTraversal<
      org.apache.tinkerpop.gremlin.structure.Vertex,
      org.apache.tinkerpop.gremlin.structure.Vertex> {

  }

  /**
   * A function denoting a {@code GraphTraversal} that starts at vertices, and ends at edges.
   */
  interface ToEdge extends SubTraversal<
      org.apache.tinkerpop.gremlin.structure.Vertex, Edge> {

  }
} @Data
@Builder
@AllArgsConstructor
@Accessors(fluent = true, chain = true)
@RequiredArgsConstructor(staticName = "of")
@SuppressWarnings("PMD.TooManyStaticImports")
public class HasKeys implements ElementTo.Element {

  private final org.apache.tinkerpop.gremlin.object.structure.Element element;

  private Class<? extends Annotation> keyType;

  @SuppressWarnings("PMD.ShortMethodName")
  public static HasKeys of(org.apache.tinkerpop.gremlin.object.structure.Element element,
      Class<? extends Annotation> keyType) {
    return HasKeys.builder()
        .element(element)
        .keyType(keyType)
        .build();
  }

  @Override
  @SneakyThrows
  public GraphTraversal<Element, Element> apply(GraphTraversal<Element, Element> traversal) {
    traversal.hasLabel(element.label());
    List<Field> fields;
    if (keyType != null) {
      if (is(keyType, PrimaryKey.class)) {
        fields = primaryKeyFields(element);
      } else if (is(keyType, OrderingKey.class)) {
        fields = orderingKeyFields(element);
      } else {
        throw org.apache.tinkerpop.gremlin.object.structure.Element.Exceptions
            .invalidAnnotationType(keyType);
      }
    } else {
      fields = keyFields(element);
    }
    for (Field field : fields) {
      String key = propertyKey(field);
      Object value = propertyValue(field, element);
      if (isMissing(value)) {
        throw org.apache.tinkerpop.gremlin.object.structure.Element.Exceptions.requiredKeysMissing(
            element.getClass(), key);
      }
      traversal.has(key, value);
    }
    return traversal;
  }
} @SuppressWarnings({"PMD.ShortMethodName"})
public static boolean is(Class<?> type, Object that) {
  return that != null && is(type, that.getClass());
} public static boolean isCollection(Object object) {
  return object != null && isCollection(object.getClass());
} public static boolean isEdge(Object object) {
  return object != null && isEdge(object.getClass());
} public static boolean isElement(Class<?> type) {
  return is(type, Element.class);
} public static boolean isFunctional(Class<?> type) {
  return is(type, Function.class);
} public static boolean isList(Object object) {
  return object != null && isList(object.getClass());
} public static boolean isSet(Object object) {
  return object != null && isSet(object.getClass());
} public static boolean isVertex(Object object) {
  return object != null && isVertex(object.getClass());
}
import org.apache.tinkerpop.gremlin.object.edges.Develops;
import org.apache.tinkerpop.gremlin.object.vertices.Person;
import org.apache.tinkerpop.gremlin.object.structure.Edge;
import org.apache.tinkerpop.gremlin.object.structure.Vertex;
import org.apache.tinkerpop.gremlin.object.traversal.library.HasKeys;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.PriorityQueue;
import static org.apache.tinkerpop.gremlin.object.reflect.Classes.is;
import static org.apache.tinkerpop.gremlin.object.reflect.Classes.isCollection;
import static org.apache.tinkerpop.gremlin.object.reflect.Classes.isEdge;
import static org.apache.tinkerpop.gremlin.object.reflect.Classes.isElement;
import static org.apache.tinkerpop.gremlin.object.reflect.Classes.isFunctional;
import static org.apache.tinkerpop.gremlin.object.reflect.Classes.isList;
import static org.apache.tinkerpop.gremlin.object.reflect.Classes.isSet;
import static org.apache.tinkerpop.gremlin.object.reflect.Classes.isVertex;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.tinkerpop.gremlin.object.reflect;




/**
 * Assert that the {@link Classes#is*} methods behave as expected.
 *
 * @author Karthick Sankarachary (http://github.com/karthicks)
 */
public class ClassesTest extends ReflectTest {

  @Test
  public void testIsElement() {
    assertTrue(isElement(Person.class));
    assertTrue(isElement(Develops.class));
  }

  @Test
  public void testIsVertex() {
    assertTrue(isVertex(Person.class));
    assertFalse(isVertex(Develops.class));
  }

  @Test
  public void testIsEdge() {
    assertFalse(isEdge(Person.class));
    assertTrue(isEdge(Develops.class));
  }

  @Test
  public void testIsList() {
    assertFalse(isList(Person.class));
    assertTrue(isList(Arrays.asList(develops)));
  }

  @Test
  public void testIsSet() {
    assertTrue(isSet(new HashSet<>()));
    assertFalse(isSet(Person.class));
  }

  @Test
  public void testIsCollection() {
    assertTrue(isCollection(new ArrayList<>()));