// Path: stardao-core/src/main/java/io/stardog/stardao/annotations/Required.java
// public interface Required extends Default {
// }
// 
// Path: stardao-core/src/main/java/io/stardog/stardao/core/Update.java
// @AutoValue
// @JsonDeserialize(using = UpdateDeserializer.class)
// @JsonSerialize(using = UpdateSerializer.class)
// public abstract class Update<P> {
//     public abstract P getPartial();
//     public abstract Set<String> getSetFields();
//     public abstract Set<String> getRemoveFields();
// 
//     public static <T> Update<T> of(T setObject, Set<String> setFields) {
//         return new AutoValue_Update<>(setObject, setFields, ImmutableSet.of());
//     }
// 
//     public static <T> Update<T> of(T setObject, Set<String> setFields, Set<String> removeFields) {
//         return new AutoValue_Update<>(setObject, setFields, removeFields);
//     }
// 
//     public boolean isEmpty() {
//         return getSetFields().isEmpty() && getRemoveFields().isEmpty();
//     }
// 
//     public Set<String> getUpdateFields() {
//         return Sets.union(getSetFields(), getRemoveFields());
//     }
// 
//     public boolean isUpdateField(String field) {
//         return getSetFields().contains(field) || getRemoveFields().contains(field);
//     }
// }
// 
// Path: stardao-core/src/main/java/io/stardog/stardao/core/field/Field.java
// @AutoValue
// public abstract class Field {
//     public abstract String getName();
//     public abstract String getStorageName();
//     public abstract boolean isOptional();
//     public abstract boolean isCreatable();
//     public abstract boolean isUpdatable();
// 
//     public abstract Field.Builder toBuilder();
//     public static Field.Builder builder() { return new AutoValue_Field.Builder(); }
// 
//     @AutoValue.Builder
//     public abstract static class Builder {
//         public abstract Builder name(String name);
//         public abstract Builder storageName(String storageName);
//         public abstract Builder optional(boolean optional);
//         public abstract Builder creatable(boolean creatable);
//         public abstract Builder updatable(boolean updatable);
//         public abstract Field build();
//     }
// }
// 
// Path: stardao-core/src/main/java/io/stardog/stardao/core/field/FieldData.java
// @AutoValue
// public abstract class FieldData {
//     @Nullable
//     public abstract Field getId();
//     @Nullable
//     public abstract Field getCreatedAt();
//     @Nullable
//     public abstract Field getCreatedBy();
//     @Nullable
//     public abstract Field getUpdatedAt();
//     @Nullable
//     public abstract Field getUpdatedBy();
//     public abstract Map<String,Field> getMap();
// 
//     public abstract Builder toBuilder();
//     public static FieldData.Builder builder() {
//         return new AutoValue_FieldData.Builder();
//     }
// 
//     @AutoValue.Builder
//     public abstract static class Builder {
//         public abstract Builder id(Field id);
//         public abstract Builder createdAt(Field field);
//         public abstract Builder createdBy(Field field);
//         public abstract Builder updatedAt(Field field);
//         public abstract Builder updatedBy(Field field);
//         public abstract Builder map(Map<String,Field> fields);
//         public abstract FieldData build();
//     }
// }
// 
// Path: stardao-core/src/main/java/io/stardog/stardao/exceptions/DataValidationException.java
// public class DataValidationException extends DataException {
//     private final List<ValidationError> errors;
// 
//     public DataValidationException(List<ValidationError> errors) {
//         this.errors = errors;
//     }
// 
//     public List<ValidationError> getErrors() {
//         return errors;
//     }
// 
//     @Override
//     public String getMessage() {
//         StringBuilder sb = new StringBuilder();
//         for (ValidationError error : errors) {
//             sb.append(error.toString());
//             sb.append("; ");
//         }
//         return sb.toString().substring(0, sb.toString().length()-2);
//     }
// }


import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableList;
import io.stardog.stardao.annotations.Required;
import io.stardog.stardao.core.Update;
import io.stardog.stardao.core.field.Field;
import io.stardog.stardao.core.field.FieldData;
import io.stardog.stardao.exceptions.DataValidationException;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.groups.Default;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
        Set<ConstraintViolation<Object>> violations = validator.validate(update.getPartial(), Default.class);
        Set<String> errorFields = new HashSet<>();
        for (ConstraintViolation<?> cv : violations) {
            String field = cv.getPropertyPath().toString();
            if (updateFields.contains(field) && !errorFields.contains(field)) {
                errors.add(ValidationError.of(field, cv.getMessage()));
                errorFields.add(field);
            }
        }

        return errors.build();
    }

    public boolean validateModel(Object model) {
        List<ValidationError> errors = getModelValidationErrors(model, Default.class);
        if (!errors.isEmpty()) {
            throw new DataValidationException(errors);
        }
        return true;
    }

    public boolean validateCreate(Object create, FieldData fieldData) {
        List<ValidationError> errors = getCreateValidationErrors(create, fieldData);
        if (!errors.isEmpty()) {
            throw new DataValidationException(errors);
        }
        return true;
    }

    public boolean validateUpdate(Update<?> update, FieldData fieldData) {
// Path: stardao-core/src/main/java/io/stardog/stardao/annotations/Required.java
// public interface Required extends Default {
// }
// 
// Path: stardao-core/src/main/java/io/stardog/stardao/core/Update.java
// @AutoValue
// @JsonDeserialize(using = UpdateDeserializer.class)
// @JsonSerialize(using = UpdateSerializer.class)
// public abstract class Update<P> {
//     public abstract P getPartial();
//     public abstract Set<String> getSetFields();
//     public abstract Set<String> getRemoveFields();
// 
//     public static <T> Update<T> of(T setObject, Set<String> setFields) {
//         return new AutoValue_Update<>(setObject, setFields, ImmutableSet.of());
//     }
// 
//     public static <T> Update<T> of(T setObject, Set<String> setFields, Set<String> removeFields) {
//         return new AutoValue_Update<>(setObject, setFields, removeFields);
//     }
// 
//     public boolean isEmpty() {
//         return getSetFields().isEmpty() && getRemoveFields().isEmpty();
//     }
// 
//     public Set<String> getUpdateFields() {
//         return Sets.union(getSetFields(), getRemoveFields());
//     }
// 
//     public boolean isUpdateField(String field) {
//         return getSetFields().contains(field) || getRemoveFields().contains(field);
//     }
// }
// 
// Path: stardao-core/src/main/java/io/stardog/stardao/core/field/Field.java
// @AutoValue
// public abstract class Field {
//     public abstract String getName();
//     public abstract String getStorageName();
//     public abstract boolean isOptional();
//     public abstract boolean isCreatable();
//     public abstract boolean isUpdatable();
// 
//     public abstract Field.Builder toBuilder();
//     public static Field.Builder builder() { return new AutoValue_Field.Builder(); }
// 
//     @AutoValue.Builder
//     public abstract static class Builder {
//         public abstract Builder name(String name);
//         public abstract Builder storageName(String storageName);
//         public abstract Builder optional(boolean optional);
//         public abstract Builder creatable(boolean creatable);
//         public abstract Builder updatable(boolean updatable);
//         public abstract Field build();
//     }
// }
// 
// Path: stardao-core/src/main/java/io/stardog/stardao/core/field/FieldData.java
// @AutoValue
// public abstract class FieldData {
//     @Nullable
//     public abstract Field getId();
//     @Nullable
//     public abstract Field getCreatedAt();
//     @Nullable
//     public abstract Field getCreatedBy();
//     @Nullable
//     public abstract Field getUpdatedAt();
//     @Nullable
//     public abstract Field getUpdatedBy();
//     public abstract Map<String,Field> getMap();
// 
//     public abstract Builder toBuilder();
//     public static FieldData.Builder builder() {
//         return new AutoValue_FieldData.Builder();
//     }
// 
//     @AutoValue.Builder
//     public abstract static class Builder {
//         public abstract Builder id(Field id);
//         public abstract Builder createdAt(Field field);
//         public abstract Builder createdBy(Field field);
//         public abstract Builder updatedAt(Field field);
//         public abstract Builder updatedBy(Field field);
//         public abstract Builder map(Map<String,Field> fields);
//         public abstract FieldData build();
//     }
// }
// 
// Path: stardao-core/src/main/java/io/stardog/stardao/exceptions/DataValidationException.java
// public class DataValidationException extends DataException {
//     private final List<ValidationError> errors;
// 
//     public DataValidationException(List<ValidationError> errors) {
//         this.errors = errors;
//     }
// 
//     public List<ValidationError> getErrors() {
//         return errors;
//     }
// 
//     @Override
//     public String getMessage() {
//         StringBuilder sb = new StringBuilder();
//         for (ValidationError error : errors) {
//             sb.append(error.toString());
//             sb.append("; ");
//         }
//         return sb.toString().substring(0, sb.toString().length()-2);
//     }
// }


// Path: stardao-core/src/main/java/io/stardog/stardao/validation/ModelValidator.java
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableList;
import io.stardog.stardao.annotations.Required;
import io.stardog.stardao.core.Update;
import io.stardog.stardao.core.field.Field;
import io.stardog.stardao.core.field.FieldData;
import io.stardog.stardao.exceptions.DataValidationException;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.groups.Default;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

        Set<ConstraintViolation<Object>> violations = validator.validate(update.getPartial(), Default.class);
        Set<String> errorFields = new HashSet<>();
        for (ConstraintViolation<?> cv : violations) {
            String field = cv.getPropertyPath().toString();
            if (updateFields.contains(field) && !errorFields.contains(field)) {
                errors.add(ValidationError.of(field, cv.getMessage()));
                errorFields.add(field);
            }
        }

        return errors.build();
    }

    public boolean validateModel(Object model) {
        List<ValidationError> errors = getModelValidationErrors(model, Default.class);
        if (!errors.isEmpty()) {
            throw new DataValidationException(errors);
        }
        return true;
    }

    public boolean validateCreate(Object create, FieldData fieldData) {
        List<ValidationError> errors = getCreateValidationErrors(create, fieldData);
        if (!errors.isEmpty()) {
            throw new DataValidationException(errors);
        }
        return true;
    }

    public boolean validateUpdate(Update<?> update, FieldData fieldData) {
        List<ValidationError> errors = getUpdateValidationErrors(update, fieldData);