public interface CopyCommand {

    /**
     * @param entityManager Entity manager reference.
     * @param entityList List of entities.
     * @param <E> JPA managed entity type.
     */
    <E extends Serializable> void insert(EntityManager entityManager, CopyList<E> entityList);

} @SuppressWarnings("serial")
public class CopyList<E extends Serializable> extends ArrayList<E> {

    private String alternateTableName;


    public CopyList() {
        super();
    }


    public CopyList(Collection<? extends E> c) {
        super(c);
    }


    public CopyList(int initialCapacity) {
        super(initialCapacity);
    }


    /**
     * @return Alternate name of table to use.
     */
    public String getAlternateTableName() {
        return alternateTableName;
    }


    /**
     * @param name Alternate name to use for the table (useful for directly inserting into partition child 
     * tables.
     */
    public void setAlternateTableName(String name) {
        this.alternateTableName = name;
    }

} public enum Color {

    RED("red"), //
    GREEN("green"), //
    BLUE("blue"), //
    BLACK("black"), // Black color will be converted to null value.
    ;
    
    private String code;


    private Color(String code) {
        this.code = code;
    }

    private static Map<String, Color> enumByCode = new HashMap<>();

    static {
        for (Color e : values()) {
            if (enumByCode.get(e.getCode()) != null) {
                throw new RuntimeException("Duplicate code found: " + e);
            }
            enumByCode.put(e.getCode(), e);
        }
    }


    public static Color forCode(String code) {
        Color value = enumByCode.get(code);
        if (value == null) {
            throw new RuntimeException("Null value sent.");
        }
        return value;
    }


    public String getCode() {
        return code;
    }
}
 @SuppressWarnings("serial")
@Entity(name = "embed_override")
public class EmbedOverride implements Serializable {

    private VehicleIdentifier identifier;
    private String owner;
    private String state;


    @AttributeOverrides({ @AttributeOverride(name = "make", column = @Column(name = "my_make", nullable = false)),
            @AttributeOverride(name = "model", column = @Column(name = "my_model")),
            @AttributeOverride(name = "year", column = @Column(name = "my_year", nullable = false)) })
    public VehicleIdentifier getIdentifier() {
        return identifier;
    }


    public void setIdentifier(VehicleIdentifier identifier) {
        this.identifier = identifier;
    }


    @Id
    @Column(name = "owner", nullable = false, unique = true)
    public String getOwner() {
        return owner;
    }


    public void setOwner(String owner) {
        this.owner = owner;
    }


    @Column(name = "state")
    public String getState() {
        return state;
    }


    public void setState(String state) {
        this.state = state;
    }

} @SuppressWarnings("serial")
@Entity(name = "embed_simple")
public class EmbedSimple implements Serializable {

    private VehicleIdentifier identifier;
    private String owner;
    private String state;


    public VehicleIdentifier getIdentifier() {
        return identifier;
    }


    public void setIdentifier(VehicleIdentifier identifier) {
        this.identifier = identifier;
    }


    @Id
    @Column(name = "owner", nullable = false, unique = true)
    public String getOwner() {
        return owner;
    }


    public void setOwner(String owner) {
        this.owner = owner;
    }


    @Column(name = "state")
    public String getState() {
        return state;
    }


    public void setState(String state) {
        this.state = state;
    }

} @SuppressWarnings("serial")
@Entity
@Table(name = "exotic_types")
public class ExoticTypes implements java.io.Serializable {

    private String login;
    private BitSet countries;
    private Set<String> authorizations;
    private List<Long> scores;
    private List<Long> gpa;
    private Status status;
    private String custom;
    private Color color;
    private int total;
    private List<String> capitals = new ArrayList<>();
    private Student student;
    private byte[] image;
    

    @Id
    @Column(name = "login", unique = true, nullable = false)
    public String getLogin() {
        return this.login;
    }


    public void setLogin(String login) {
        this.login = login;
    }


    @Column(name = "countries", nullable = false, length = 7)
    @Type(type = "com.eclecticlogic.pedal.provider.hibernate.dialect.PostgresqlBitStringUserType", parameters = @Parameter(name = PostgresqlBitStringUserType.BIT_LENGTH, value = "7"))
    @CopyAsBitString
    public BitSet getCountries() {
        return this.countries;
    }


    public void setCountries(BitSet countries) {
        this.countries = countries;
    }


    @Column(name = "authorizations", nullable = false)
    @Type(type = "com.eclecticlogic.pedal.provider.hibernate.SetType", parameters = @Parameter(name = ArrayType.DIALECT_PRIMITIVE_NAME, value = PostgresqlArrayPrimitiveName.STRING))
    public Set<String> getAuthorizations() {
        return this.authorizations;
    }


    public void setAuthorizations(Set<String> authorizations) {
        this.authorizations = authorizations;
    }


    @Column(name = "scores")
    @Type(type = "com.eclecticlogic.pedal.provider.hibernate.ListType", parameters = { @Parameter(name = ArrayType.DIALECT_PRIMITIVE_NAME, value = PostgresqlArrayPrimitiveName.LONG) })
    public List<Long> getScores() {
        return this.scores;
    }


    public void setScores(List<Long> scores) {
        this.scores = scores;
    }


    @Column(name = "gpa")
    @Type(type = "com.eclecticlogic.pedal.provider.hibernate.ListType", parameters = {
            @Parameter(name = ArrayType.DIALECT_PRIMITIVE_NAME, value = PostgresqlArrayPrimitiveName.LONG),
            @Parameter(name = ArrayType.EMPTY_IS_NULL, value = "false") })
    public List<Long> getGpa() {
        return gpa;
    }


    public void setGpa(List<Long> gpas) {
        this.gpa = gpas;
    }


    @Column(name = "status", nullable = false, length = 2)
    @Convert(converter = StatusConverter.class)
    public Status getStatus() {
        return status;
    }


    public void setStatus(Status status) {
        this.status = status;
    }


    @CopyConverter(UppercaseConversionHelper.class)
    @Column(name = "custom", nullable = false)
    public String getCustom() {
        return custom;
    }


    public void setCustom(String custom) {
        this.custom = custom;
    }


    @Column(name = "color")
    @Convert(converter = ColorConverter.class)
    public Color getColor() {
        return color;
    }


    
    public void setColor(Color color) {
        this.color = color;
    }

    
    /**
     * To test exclusion of fields with parameters since they are not java-bean properties and return type is embeddable.
     * @param input
     * @return
     */
    public PlanetId getSomeValue(int input) {
        return new PlanetId("test", input);
    }


    @Column(name = "total", nullable = false)
    public int getTotal() {
        return total;
    }


    public void setTotal(int total) {
        this.total = total;
    }


    @Column(name = "capitals")
    @Type(type = "com.eclecticlogic.pedal.provider.hibernate.ListType", parameters = {
            @Parameter(name = ArrayType.DIALECT_PRIMITIVE_NAME, value = PostgresqlArrayPrimitiveName.STRING)})
    @CopyEmptyAsNull
    public List<String> getCapitals() {
        return capitals;
    }


    public void setCapitals(List<String> capitals) {
        this.capitals = capitals;
    }


    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "student_id", nullable = false)
    public Student getStudent() {
        return student;
    }


    public void setStudent(Student student) {
        this.student = student;
    }


    @Transient // Transient should prevent embeddable from being added to copy list.
    public VehicleIdentifier getVehicleIdentifier() {
        return null;
    }


    public void setVehicleIdentifier() {
        // noop
    }


    @Column(name = "image_data")
    public byte[] getImage() {
        return image;
    }


    public void setImage(byte[] image) {
        this.image = image;
    }
}
 @SuppressWarnings("serial")
@Entity
@Table(name = "planet")
public class Planet implements Serializable {

    private PlanetId id;
    private int distance;


    @EmbeddedId
    @AttributeOverrides({
            @AttributeOverride(name = "name", column = @Column(name = "name", nullable = false)),
            @AttributeOverride(name = "position", column = @Column(name = "position", nullable = false)) })
    public PlanetId getId() {
        return id;
    }


    public void setId(PlanetId id) {
        this.id = id;
    }


    @Column(name = "distance")
    public int getDistance() {
        return distance;
    }


    public void setDistance(int distance) {
        this.distance = distance;
    }

} @SuppressWarnings("serial")
@Embeddable
public class PlanetId implements Serializable {

    private String name;
    private int position;


    public PlanetId() {
        super();
    }


    public PlanetId(String name, int position) {
        this.name = name;
        this.position = position;
    }


    public String getName() {
        return name;
    }


    public void setName(String name) {
        this.name = name;
    }


    public int getPosition() {
        return position;
    }


    public void setPosition(int position) {
        this.position = position;
    }


    @Override
    public int hashCode() {
        return Objects.hash(getName(), getPosition());
    }


    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        } else if (obj instanceof PlanetId == false) {
            return false;
        } else {
            PlanetId typed = (PlanetId) obj;
            return Objects.equals(this.getName(), typed.getName()) && this.getPosition() == typed.getPosition();
        }
    }
} public enum Status {

    ACTIVE("AC"), //
    INACTIVE("IC"), //
    ;
    
    private String code;


    private Status(String code) {
        this.code = code;
    }

    private static Map<String, Status> enumByCode = new HashMap<>();

    static {
        for (Status e : values()) {
            if (enumByCode.get(e.getCode()) != null) {
                throw new RuntimeException("Duplicate code found: " + e);
            }
            enumByCode.put(e.getCode(), e);
        }
    }


    public static Status forCode(String code) {
        return enumByCode.get(code);
    }


    public String getCode() {
        return code;
    }
} @SuppressWarnings("serial")
@Entity
@Table(name = "student")
@AttributeOverrides(value = {@AttributeOverride(name = "idBase", column = @Column(name = "id", unique = true, nullable = false, length = 36))})
public class Student extends BaseStudent {

    private String name;
    private String zone;
    private float gpa;
    private Date insertedOn;


    @Transient
    public void setMiddleName(String value) {
        // This is to ensure that the copy command doesn't fail if there are setters without getters.
    }


    @Column(name = "name", length = 25, nullable = false)
    public String getName() {
        return name;
    }


    public void setName(String name) {
        this.name = name;
    }


    @Column(name = "gpa", nullable = false)
    public float getGpa() {
        return gpa;
    }


    public void setGpa(float gpa) {
        this.gpa = gpa;
    }


    @Column(name = "zone", length = 5)
    public String getZone() {
        return zone;
    }


    public void setZone(String zone) {
        this.zone = zone;
    }


    @Column(name = "inserted_on", nullable = false)
    public Date getInsertedOn() {
        return insertedOn;
    }


    public void setInsertedOn(Date insertedOn) {
        this.insertedOn = insertedOn;
    }

} @Embeddable
public class VehicleIdentifier {

    private String make;
    private String model;
    private int year;
    
    @Column(name = "make", nullable = false)
    public String getMake() {
        return make;
    }
    
    public void setMake(String make) {
        this.make = make;
    }
    
    @Column(name = "model")
    public String getModel() {
        return model;
    }
    
    public void setModel(String model) {
        this.model = model;
    }
    
    @Column(name = "year", nullable = false)
    public int getYear() {
        return year;
    }
    
    public void setYear(int year) {
        this.year = year;
    }
    
    
    
    
} public interface ProviderAccess {

    /**
     * @return Name of schema connected to. Empty string is the schema name is the default one.
     */
    public String getSchemaName();


    /**
     * @param entityClass Entity class
     * @return Name of table.
     */
    public String getTableName(Class<? extends Serializable> entityClass);

}
import com.eclecticlogic.pedal.dialect.postgresql.CopyCommand;
import com.eclecticlogic.pedal.dialect.postgresql.CopyList;
import com.eclecticlogic.pedal.dm.Color;
import com.eclecticlogic.pedal.dm.EmbedOverride;
import com.eclecticlogic.pedal.dm.EmbedSimple;
import com.eclecticlogic.pedal.dm.ExoticTypes;
import com.eclecticlogic.pedal.dm.Planet;
import com.eclecticlogic.pedal.dm.PlanetId;
import com.eclecticlogic.pedal.dm.Status;
import com.eclecticlogic.pedal.dm.Student;
import com.eclecticlogic.pedal.dm.VehicleIdentifier;
import com.eclecticlogic.pedal.provider.ProviderAccess;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.BitSet;
import java.util.Date;

        Student student = new Student();
        student.setGpa(4.0f);
        student.setIdBase("exotic_student");
        student.setMiddleName("joe1");
        student.setName("schmoe1");
        student.setZone("z");
        student.setInsertedOn(new Date());
        entityManager.persist(student);

        // The copy-command can insert 100k of these per second.
        for (int i = 0; i < 10; i++) {
            ExoticTypes et = new ExoticTypes();
            et.setLogin("copyCommand" + i);
            BitSet bs = new BitSet(7);
            bs.set(1);
            bs.set(3);
            bs.set(4);
            et.setCountries(bs);
            et.setAuthorizations(Sets.newHashSet("a", "b", "b", "c"));
            if (i != 9) {
                et.setScores(Lists.newArrayList(1L, 2L, 3L));
            } else {
                et.setScores(Lists.<Long> newArrayList());
            }
            et.setStatus(Status.ACTIVE);
            et.setCustom("this will be made uppercase");
            et.setColor(Color.BLACK); // Black is converted to null. This is to test and ensure null value is
             // conversion is properly handled.
            et.setTotal(i * 10);
            et.setStudent(student);
            et.setImage(Files.readAllBytes(Paths.get(".", "src/test/resources/binary.data")));
            list.add(et);
        }

        copyCommand.insert(entityManager, list);
        Assert.assertNotNull(entityManager.find(ExoticTypes.class, "copyCommand0"));
        Assert.assertEquals(entityManager.find(ExoticTypes.class, "copyCommand0").getCustom(),
                "THIS WILL BE MADE UPPERCASE");
        Assert.assertNotNull(entityManager.find(ExoticTypes.class, "copyCommand1"));
        Assert.assertEquals(entityManager.find(ExoticTypes.class, "copyCommand0").getAuthorizations(),
                Sets.newHashSet("b", "c", "a"));

        // Nullable converted value should be written as null.
        Assert.assertNull(entityManager.find(ExoticTypes.class, "copyCommand0").getColor());
    }


    @Test
    @Transactional
    public void testBulkCopyCommand() {
        CopyList<ExoticTypes> list = new CopyList<>();

        Student student = new Student();
        student.setGpa(4.0f);
        student.setIdBase("exotic_student");
        student.setMiddleName("joe1");
        student.setName("schmoe1");
        student.setZone("z");
        student.setInsertedOn(new Date());
        entityManager.persist(student);

        int power = 0;
        double limit = Math.pow(2, 20);
        for (int i = 0; i <= limit; i++) {
            ExoticTypes et = new ExoticTypes();
            et.setLogin("copyCommand" + i);
            BitSet bs = new BitSet(7);
            bs.set(1);
            bs.set(3);
            bs.set(4);
            et.setCountries(bs);
            et.setAuthorizations(Sets.newHashSet("a", "b", "b", "c"));
            if (i != 9) {
                et.setScores(Lists.newArrayList(1L, 2L, 3L));
            } else {
                et.setScores(Lists.<Long> newArrayList());
            }
            et.setStatus(Status.ACTIVE);
            et.setCustom("this will be made uppercase");
            et.setColor(Color.BLACK); // Black is converted to null. This is to test and ensure null value is
            // conversion is properly handled.
            et.setTotal(i * 10);
            et.setStudent(student);
            // et.setImage too much memory used.
            list.add(et);

            if (list.size() % Math.pow(2, power) == 0) {
                copyCommand.insert(entityManager, list);
                list.clear();
                power++;
            }
        }
    }

    @Test
    @Transactional
    public void testAttributeOverrideWithCopyCommand() {
        CopyList<Student> list = new CopyList<>();
        {
            Student student = new Student();
            student.setGpa(4.0f);
            student.setIdBase("attrib");
            student.setMiddleName("joe1");
            student.setName("schmoe1");
            student.setZone("z");
            student.setInsertedOn(new Date());
            list.add(student);
        }
        copyCommand.insert(entityManager, list);
        Assert.assertNotNull(entityManager.find(Student.class, "attrib"));
    }


    @Test
    @Transactional
    public void testCopyCommandWithEmbeddedId() {
        CopyList<Planet> list = new CopyList<>();
        {
            Planet p = new Planet();
            PlanetId id = new PlanetId();