Via java reflection, set and take values of inherited variables

Asked

Viewed 2,814 times

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 recovering its values, receiving a String at runtime.

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

1st Method to search for field in the current class and in the parent classes, by their 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;

    }

2º Method to generate a String containing all values of fields separated by lines.

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;
}

3º Receive a String set the value of each field per line 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){}
                }
            }
        }
    }
}

However I tested and even the names of the variables passed as parameter are correct, an exception occurs stating that these were not found. Could someone please give a hint about some mistake I’m making, or indicate a topic regarding this subject.

1 answer

3


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

On the other hand, I see no glaring errors in the code posted, other than some bad practices (catch untreated, for example).

Testing

I did a test reconstructing some parts of the code and asumindo 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;
    }

}

So I ran 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 as expected:

valor1 value2

Completion

The problem you are facing must be a misconception as to the amounts received or may be a flaw in the methods missing from your question (of which I mentioned two at the beginning of the answer.

View the stack of errors or run the program in debug mode to see which line the exception occurs and which value is "breaking" its implementation.

Suggestions

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

Also, there are many reflection Apis out there that would make your life easier. Consider Apache Commons Beanutils. He has a method populate() that receives a POJO is a map. So, all you would need to do is break your "protocol" string into names and values, add it to 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);

Anyway, reinventing the wheel is cool because of knowledge, but using robust solutions from well-tested libraries is much better to avoid problems in production.

  • Hi thanks for the help ,then getConstValues returns a list of item names of headers and getFieldNameByHeader takes a header name and turns into the name of a class variable

  • 1

    @user5020 You have to ensure that the name is exactly the same as the attributes. For example, if there is a header nome, the class attribute has to be something like private String nome.

  • yes that’s right, I’ll show you some examples of search, Requesthttp has the following fields protected String headerAccept;
 protected String headerAcceptCharset;
 protected String headerAcceptEncoding;
 protected String headerAcceptLanguage; and put a print on the name of the searched field each time it performs a search 
headerAccept 
headerAcceptCharset 
headerAcceptEncoding 
headerAcceptEncoding 
headerAcceptEncoding 
headerAcceptEncoding 
headerAcceptLanguage 


  • 1

    Guy discovered was the getFieldNameByHeader in it I use the replace("-","") method; and ended up getting a space at the end, so I added the Trim() method; , Fight for the tips.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.