martedì 11 gennaio 2011

Java: Reflect on this [ENG]

Reflection in Java is a powerful tool, expecially useful when your code must get in touch with the outer world (configuration files, database, http protocol...). Here's an example, a simple parser for a CSV string where every value has a tag:

id=1112396889697; t=22740834120; 
x=184549969; y=8389273; f=89; 
q0=0.18810; q1=0.07500; q2=-0.23573; q3=0.96616

What I would like to do here is parsing the data into an object with (a subset of) the fields in each line. The solution is overly simplified, but it just works:

import java.lang.reflect.Field;

public class Sample
{

    class SampleData
    {
        public Long t = new Long(0);
    
        public Long x = new Long(0);
        public Long y = new Long(0);
        public Long f = new Long(0);
    
        public Double q0 = new Double(0);
        public Double q1 = new Double(0);
        public Double q2 = new Double(0);
        public Double q3 = new Double(0);
    }

    private SampleData data = new SampleData();
    
    public Sample(String taggedCsv)
    {
        if (taggedCsv != null && !"".equals(taggedCsv))
        {
            String[] chunks = taggedCsv.split(";");
            for (String chunk : chunks)
            {
                chunk = chunk.trim();
                String[] parts = chunk.split("=");
                String tag = parts[0].trim();
                String value = parts[1].trim();
                try
                {
                    Class<? extends SampleData> class1 = data.getClass();
                    Field f = class1.getField(tag);
                    if (f!=null)
                    {
                        if (f.getType().equals(java.lang.Double.class))
                        {
                            f.set(data, new Double(value));
                        }
                        else
                        if (f.getType().equals(java.lang.Long.class))
                        {
                            f.set(data, new Long(value));
                        }
                    }
                }
                catch (Exception e)
                {
                    System.out.println(e.getMessage());
                }
            }
        }
    }

    public long getT()
    {
        return data.t.longValue();
    }

    public double getX()
    {
        return data.x.longValue();
    }

    public double getY()
    {
        return data.y.longValue();
    }

    public double getF()
    {
        return data.f.longValue();
    }

    public double getQ0()
    {
        return data.q0.doubleValue();
    }

    public double getQ1()
    {
        return data.q1.doubleValue();
    }

    public double getQ2()
    {
        return data.q2.doubleValue();
    }

    public double getQ3()
    {
        return data.q3.doubleValue();
    }

}

It seems like it's doing its job just fine:

    @Test
    public void firstTest()
    {
        Sample a = new Sample(
"id=1112396889697; t=22740834120; " + 
"x=184549969; y=8389273; f=89; " +
"q0=0.18810; q1=0.07500; q2=-0.23573; q3=0.96616"); 
        assertTrue(22740834120L==a.getT());
        assertTrue(184549969L==a.getX());
        assertTrue(8389273L==a.getY());
        
    }

NOTE: there is an awkward thing in the code up there. To obtain encapsulation I had to use a PRIVATE class (DataSample) with PUBLIC fields because getField() can not access PRIVATE fields. There are other ways round, but they are not as lean. Still don't like it, though.

0 commenti: