Attributes in Java

Yes, Java has them. They are called annotations. Finding a complete example is hard to find on the web. But this is how you use them to give a real-world example of reading and parsing TIGER EDGE DBF files using geotools library.

import org.geotools.data.shapefile.dbf.DbaseFileReader;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Retention;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
    @Retention(value=RetentionPolicy.RUNTIME)
    public @interface Column {
        int value() default -1;
    }
public class TigerEdge {
    @Column(0)
    private String stateFP;
    @Column(1)
    private String countyFP;
    @Column(2)
    private long tlid;
    @Column(3)
    private long tfidl;
    @Column(4)
    private long tfidr;
    @Column(5)
    private String mtfcc;
    @Column(6)
    private String fullName;
    @Column(7)
    private String smid;
    @Column(8)
    private String lfromadd;
    @Column(9)
    private String ltoadd;
    @Column(10)
    private String rfromadd;
    @Column(11)
    private String rtoadd;
    @Column(12)
    private String zipl;
    @Column(13)
    private String zipr;
    @Column(14)
    private String featcat;
    @Column(15)
    private String hydroflg;
    @Column(16)
    private String railflg;
    @Column(17)
    private String roadflg;
    @Column(18)
    private String olfflg;
    @Column(19)
    private String passflg;
    @Column(20)
    private String divroad;
    @Column(21)
    private String exttyp;
    @Column(22)
    private String ttyp;
    @Column(23)
    private String deckedroad;
    @Column(24)
    private String artpath;
    @Column(25)
    private String persist;
    @Column(26)
    private String gcseflg;
    @Column(27)
    private String offsetl;
    @Column(28)
    private String offsetr;
    @Column(29)
    private long tnidf;
    @Column(30)
    private long tnidt;
    private  TigerEdge() {}
public static TigerEdge fromDbf(DbaseFileReader.Row row) throws Exception
{
    return (TigerEdge) DbfParser.parseDbf(row, TigerEdge.class);
}
}
import org.geotools.data.shapefile.dbf.DbaseFileReader;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;

@Retention(value= RetentionPolicy.RUNTIME)
@interface Column {
    int value() default -1;
}

public class DbfParser {
    public static Object parseDbf(DbaseFileReader.Row row, Class c) throws Exception
    {
        // http://stackoverflow.com/questions/8249173/what-is-the-difference-between-getdeclaredconstructors-and-getconstructors-in-th
        Constructor ctor = c.getDeclaredConstructor();
        ctor.setAccessible(true);
        Object answer = ctor.newInstance();
        Field[] allFields = c.getDeclaredFields();
        for (Field field : allFields) {
            if (Modifier.isPrivate(field.getModifiers())) {
                // without setting the fields to be accessible, there will be an error trying to get/set it
                field.setAccessible(true);
                Type t = field.getType();
                int column = field.getAnnotation(Column.class).value();
                Object o = row.read(column);
                if (t == String.class && o.getClass() == String.class)
                {
                    field.set(answer, o);
                }
                else if (t == long.class)
                {
                    if (o.getClass() == Long.class) {
                        field.setLong(answer, (long) o);
                    }
                    else if (o.getClass() == Double.class)
                    {
                        // normally o.class MUST be equal to Long.class
                        // but looks like due to a bug in DbaseFileReader
                        // 0 is misinterpreted as 0.0 and we need a special check
                        // to take care of it
                        field.setLong(answer, ((Double)o).longValue());
                    }
                    else
                    {
                        String message = String.format("unable to parse %s expected a long or double", o);
                        throw new IllegalArgumentException(message);
                    }
                }
                else
                {
                    throw new IllegalStateException();
                }
            }
        }
        return answer;
    }
}
This entry was posted in Software. Bookmark the permalink.

Leave a comment