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.

Nessun commento: