I’m trying to implement the use of reflection and annotations, just like the solution suggested by ardayigit on how to create a JTable with POJOs with a single table model, but the problem comes with the first field of Person, which is a two-field composite key of type PersonId.
Here is the extract for creating the JTable
:
//List<Person> persons
ModelDAO model = new ModelDAO(persons);
JTable table = new JTable(model) {
@Override
public Class getColumnClass(int column) {
try {
return getValueAt(0, column).getClass();
} catch (NullPointerException e) {
return String.class;
}
}
};
here is the code of the POJO Person:
@Entity
@Table(name = "Person",
schema = "dbo",
catalog = "DB"
)
public class Person implements Serializable {
private PersonId id;
@ColumnAttribute(columnName = "t_name", order = 2, updatable = true)
private String tName;
@ColumnAttribute(columnName = "t_address", order = 4, updatable = true)
private String tAddress;
@ColumnAttribute(columnName = "t_single", order = 5, updatable = true)
private boolean tSingle;
public Person(PersonId id, String tName, String tAddress, boolean tSingle) {
this.id = id;
this.tName = tName;
this.tAddress = tAddress;
this.tSingle = tSingle;
}
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "tKey", column = @Column(name = "t_key", nullable = false, length = 8)),
@AttributeOverride(name = "tReg", column = @Column(name = "t_reg", nullable = false, length = 2))
})
public PersonId getId() {
return id;
}
public void setId(PersonId id) {
this.id = id;
}
@Column(name = "t_name", length = 100)
public String getTName() {
return tName;
}
public void setTName(String tName) {
this.tName = tName;
}
@Column(name = "t_address", length = 60)
public String getTAddress() {
return tAddress;
}
public void setTAddress(String tAddress) {
this.tAddress = tAddress;
}
@Column(name = "t_single", nullable = false, columnDefinition = "BIT")
public boolean getTSingle() {
return tSingle;
}
public void setTSingle(boolean tSingle) {
this.tSingle = tSingle;
}
}
here is PersonId:
@Embeddable
public class PersonId implements Serializable {
@ColumnAttribute(columnName = "t_key", order = 1, updatable = false)
private String tKey;
@ColumnAttribute(columnName = "t_reg", order = 3, updatable = false)
private String tReg;
public PersonId() {
}
public PersonId(String tKey, String tReg) {
this.tKey = tKey;
this.tReg = tReg;
}
@Column(name="t_key", nullable=false, length=8)
public String getTKey() {
return tKey;
}
public void setTKey(String tKey) {
this.tKey = tKey;
}
@Column(name="t_reg", nullable=false, length=2)
public String getTReg() {
return tReg;
}
public void setTReg(String tReg) {
this.tReg = tReg;
}
@Override
public int hashCode() {
int hash = 7;
hash = 79 * hash + Objects.hashCode(this.tKey);
hash = 79 * hash + Objects.hashCode(this.tReg);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final PersonId other = (PersonId) obj;
if (!Objects.equals(this.tKey, other.tKey)) {
return false;
}
if (!Objects.equals(this.tReg, other.tReg)) {
return false;
}
return true;
}
}
As you can see, I´ve modified a little the proposal of ardaigit and created ColumnAttributes and ColumnAttribute to get it work the way it does AttributeOverrides and AttributeOverridebut not sure if you got it right.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ColumnAttributes {
public ColumnAttribute[] value();
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ColumnAttribute {
String columnName();
int order();
boolean updatable();
}
At this point, the method getColumnCount
of ModelDAO returns 4, because tName
and tReg
are counted as 1 –> id
:
public class ModelDAO extends AbstractTableModel {
private final List<?> data;
public ModelDAO(List data) {
this.data = data;
}
@Override
public int getRowCount() {
return this.data.size();
}
@Override
public int getColumnCount() {
return data.get(0).getClass().getDeclaredFields().length;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
try {
Method[] methods = data.get(rowIndex).getClass().getDeclaredMethods();
Arrays.sort(methods, new ComparatorReflection<>());
return methods[columnIndex].invoke(data.get(rowIndex), (Object[]) null);
} catch (IllegalAccessException | IllegalArgumentException | SecurityException | InvocationTargetException ex) {
ex.printStackTrace();
}
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Class<?> getColumnClass(int columnIndex) {
Field[] fields = data.get(0).getClass().getDeclaredFields();
Arrays.sort(fields, new ComparatorReflection<>());
return fields[columnIndex].getType();
}
@Override
public String getColumnName(int column) {
Field[] fields = data.get(0).getClass().getDeclaredFields();
Arrays.sort(fields, new ComparatorReflection<>());
return fields[column].getAnnotation(ColumnAttribute.class).columnName();
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
Field[] fields = data.get(rowIndex).getClass().getDeclaredFields();
Arrays.sort(fields, new ComparatorReflection<>());
return fields[columnIndex].getAnnotation(ColumnAttribute.class).updatable();
}
}
Is there a way to “extract” the fields of PersonId in order to get the right column counts, values, classes and names to show them in an editable JTable
?