Via reflection in java, set and get values of inherited variables

3

I have the following class hierarchy

(POSTRequestHTTP extends ReqeustHTTP) 
(RequestHTTP extends ComunicationObjectHTTP )

Assuming that each object can have variables corresponding to an item in a header, and I have to set its values by passing a String and retrieving its values, getting a String at runtime.

In order to not have to implement in all Classes, I have implemented appendices in the class of the highest hierarchical level (CommunicatonObjectHTTP), The following methods:

1st method to search field in the current class and parent classes, by name.

protected Field getHeaderField(String fieldName)
    {
        Class current = this.getClass();
        boolean keepSearch = true;
    while(keepSearch)
    {
        try{
            return current.getDeclaredField(fieldName);

        }catch(Exception ex){}
        if((current = current.getSuperclass())== null)
        {
            keepSearch = false;
        }
    }
    return null;

    }

2nd Method to generate a String containing all field values separated by rows.

public String generateHeaders()
{
    String returnValue = "";
    for(String name : constList.getConstValues())
    {
        try{
        Field field = this.getHeaderField(this.getFieldNameByHeader(name));
        field.setAccessible(true);
        Object value =  field.get(this);

            if(value != null)
            {
                String stringvalue = ""+value;
                if(stringvalue != "")
                {
                    returnValue = returnValue + value + lineSeparator;
                }
            }
        }catch(Exception ex){System.out.println(ex);}
    }
    if(returnValue != "")
    {
        returnValue = returnValue.substring(0,returnValue.length()-   lineSeparator.length());
    }
    return returnValue;
}

3rd Get a String set the value of each field per row of a String passed as parameter.

public void loadHeaders(String protocol)
{
    if(protocol != null)
    {
        if(protocol != "")
        {
            this.headers = protocol;
            String[] lines = protocol.split(lineSeparator);
            for(String line : lines)
            {
                if(line == null)
                {
                    break;
                }
                String[] nameAndValue = line.split(nameAndValueSeparator);
                if(nameAndValue.length >= 2)
                {
                    try{
                        Field field = this.getHeaderField(this.getFieldNameByHeader(nameAndValue[0]));
                        field.setAccessible(true);
                        field.set(this,nameAndValue[1]);
                    }catch(Exception ex){}
                }
            }
        }
    }
}

But I tested and even the variable names passed as parameter are correct, an exception occurs saying that these were not found. Could someone please give a hint about some mistake I'm making, or point out a topic talking about it.

    
asked by anonymous 21.05.2014 / 23:49

1 answer

3

There are parts of your code, such as getFieldNameByHeader and getConstValues , which may be the cause of the problem.

On the other hand, I do not see any blatant errors in the posted code, other than some bad practices ( catch no treatment, for example).

Test

I did a test rebuilding some parts of the code and assuming some values.

I created the following classes:

ComunicationObjectHTTP

public class ComunicationObjectHTTP {

    protected Field getHeaderField(String fieldName) {
    Class current = this.getClass();
    boolean keepSearch = true;
    while (keepSearch) {
        try {
        return current.getDeclaredField(fieldName);

        } catch (Exception ex) {
        }
        if ((current = current.getSuperclass()) == null) {
        keepSearch = false;
        }
    }
    return null;

    }

    private String lineSeparator = "\r\n";
    private String headers;
    private String nameAndValueSeparator = "=";

    public void loadHeaders(String protocol) {
    if (protocol != null) {
        if (protocol != "") {
        this.headers = protocol;
        String[] lines = protocol.split(lineSeparator);
        for (String line : lines) {
            if (line == null) {
            break;
            }
            String[] nameAndValue = line.split(nameAndValueSeparator);
            if (nameAndValue.length >= 2) {
            try {
                Field field = this.getHeaderField(nameAndValue[0]);
                field.setAccessible(true);
                field.set(this, nameAndValue[1]);
            } catch (Exception ex) {
            }
            }
        }
        }
    }
    }
}

RequestHTTP

public class RequestHTTP extends ComunicationObjectHTTP {

    private String campo1;

    public String getCampo1() {
    return campo1;
    }   

}

POSTRequestHTTP

public class POSTRequestHTTP extends RequestHTTP {

    private String campo2;

    public String getCampo2() {
    return campo2;
    }

}

Then I executed with the following commands:

POSTRequestHTTP p = new POSTRequestHTTP();
p.loadHeaders("campo1=valor1\r\ncampo2=valor2");
System.out.println(p.getCampo1());
System.out.println(p.getCampo2());

And the result was expected:

  

value1   value2

Conclusion

The problem you are experiencing should be a misunderstanding of the received values or it may be a failure in the methods missing from your question (of which I mentioned two at the beginning of the answer.

Look at the stack of errors or run the program in debug mode to see what line the exception occurs in and the value that is breaking its implementation.

Suggestions

Would not use inheritance to inherit utility methods. I have done this many times and it only complicates things. If you create an auxiliary class that receives a POJO and a String with the values to do the processing, you do not have to make your attribute classes extend any other class, leaving your code less coupled.

In addition, there are many thought APIs out there that would make your life easier. Consider the Apache Commons Beanutils / a>. It has a populate() method that receives a POJO is a map. So all you would need to do is break your String from the "protocol" into names and values, add on a map and move on to the method.

See an example of the documentation itself (link above):

HttpServletRequest request = ...;
MyBean bean = ...;
HashMap map = new HashMap();
Enumeration names = request.getParameterNames();
while (names.hasMoreElements()) {
  String name = (String) names.nextElement();
  map.put(name, request.getParameterValues(name));
}
BeanUtils.populate(bean, map);

Finally, reinventing the wheel is legal for the sake of knowledge, but using robust solutions from well-tested libraries is much better at avoiding production problems.

    
22.05.2014 / 15:11