How can use reflection to get the property names and values from a POJO?

18,844

You need to use #getDeclaredFields() to include private fields, #getFields() only lists the public ones.

With private fields you will also run into access restriction problems, so you probably want to look into the Field#setAccessible() method as well.

Share:
18,844
cbmeeks
Author by

cbmeeks

Object.const_set("Love", Class.new { def ruby() true end });i = Love.new;i.ruby

Updated on June 17, 2022

Comments

  • cbmeeks
    cbmeeks almost 2 years

    So I'm writing an "POJO to JSON" converter. I want to be able to pass in a List<T> object and convert to JSON.

    Hopefully this will make sense

    /**
     *
         * NOT COMPLETE!!!  OBVIOUSLY!!!
     */
    public abstract class Jsonator<T> implements Serializable {
    
        private Class<T> entityClass;
        private JSONObject json;
        private JSONArray jsonArray;
    
        public Jsonator(Class<T> entityClass) {
            this.entityClass = entityClass;
        }
    
        public void convert(List<T> paObjectList) throws IllegalArgumentException, IllegalAccessException {
            json = new JSONObject();
            jsonArray = new JSONArray();
    
            try {
    
                for (Object obj : paObjectList) {
                    JSONObject objJson = new JSONObject();
    
                    Class<?> kls = obj.getClass();
    
                    Field[] fields = kls.getFields();
                    for (Field field : fields) {
                        objJson.put(field.getName(), (T) field.get(obj));
                    }
    
                    jsonArray.add(objJson);
                }
    
                json.put("results", jsonArray);
    
            }
            catch (Exception ex) {
            }
        }
    
        public String error() {
            return "ERROR";
        }
    
        public String results() {
            if (json != null) {
                return json.toJSONString();
            }
    
            return "[]";
        }
    }
    

    When I get to the Object obj section, my obj is correct. I can debug it and see the name and value of the class.

    Let's say that class is this:

    public class User {
        private firstName;
        private lastName;
    
        ... getters....setters....etc...
    
    }
    

    So that now, obj is a Site. OK, I then try to get the field names (firstName, lastName) but the fields object is empty.

    What am I doing wrong?

    Thanks

    EDIT

    I got it to work! This is not finished code, but it's doing exactly what I want for now. I've read that Google and Jackson will do this too. If someone can provide a good link on how to selectively pick properties from a POJO, then I'm all ears.

    Or better yet, I'd like to know WHY I shouldn't be doing this, this way?

    Thanks!

    Jsonator (NOT FINISHED)

    import java.io.Serializable;
    import java.lang.reflect.Field;
    import java.util.List;
    import org.json.simple.JSONArray;
    import org.json.simple.JSONObject;
    
    /**
     *
     * @author Cecil.Meeks
     */
    public abstract class Jsonator<T> implements Serializable {
    
        private Class<T> entityClass;
        private JSONObject json;
        private JSONArray jsonArray;
    
        public Jsonator(Class<T> entityClass) {
            this.entityClass = entityClass;
        }
    
        public void convert(List<T> paObjectList) throws IllegalArgumentException, IllegalAccessException {
            json = new JSONObject();
            jsonArray = new JSONArray();
    
            try {
    
                for (Object obj : paObjectList) {
                    JSONObject objJson = new JSONObject();
    
                    Class<?> kls = obj.getClass();
    
                    Field[] fields = kls.getDeclaredFields();
                    for (Field field : fields) {
                        field.setAccessible(true);
                        objJson.put(field.getName(), field.get(obj));
                    }
    
                    jsonArray.add(objJson);
                }
    
                json.put("results", jsonArray);
    
            }
            catch (SecurityException ex) {
                ex.printStackTrace();
            }
            catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    
        public String error() {
            return "ERROR";
        }
    
        public String results() {
            if (json != null) {
                return json.toJSONString();
            }
    
            return "[]";
        }
    }
    

    Site Class

    import java.io.Serializable;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.persistence.Table;
    import org.hibernate.annotations.GenericGenerator;
    
    @Entity
    @Table(name = "Sites")
    public class Site implements Serializable {
    
        private String siteKey;
        private String site;
        private String siteType;
        private String address1;
        private String address2;
        private String city;
        private String zipCode;
        private String createdBy;
        private String glCode;
    
        public Site() {
        }
    
        @Id
        @GenericGenerator(name = "generator", strategy = "guid", parameters = {})
        @GeneratedValue(generator = "generator")
        public String getSiteKey() {
            return siteKey;
        }
    
        public void setSiteKey(String siteKey) {
            this.siteKey = siteKey;
        }
    
        @Column(name = "Site", unique = true, length = 125, nullable = false)
        public String getSite() {
            return site;
        }
    
        public void setSite(String site) {
            this.site = site;
        }
    
        @Column(name = "SiteType", unique = false, length = 8, nullable = true)
        public String getSiteType() {
            return siteType;
        }
    
        public void setSiteType(String siteType) {
            this.siteType = siteType;
        }
    
        @Column(name = "Address1", unique = false, length = 125, nullable = true)
        public String getAddress1() {
            return address1;
        }
    
        public void setAddress1(String address1) {
            this.address1 = address1;
        }
    
        @Column(name = "Address2", unique = false, length = 125, nullable = true)
        public String getAddress2() {
            return address2;
        }
    
        public void setAddress2(String address2) {
            this.address2 = address2;
        }
    
        @Column(name = "City", unique = false, length = 125, nullable = true)
        public String getCity() {
            return city;
        }
    
        public void setCity(String city) {
            this.city = city;
        }
    
        @Column(name = "ZipCode", unique = false, length = 50, nullable = true)
        public String getZipCode() {
            return zipCode;
        }
    
        public void setZipCode(String zipCode) {
            this.zipCode = zipCode;
        }
    
        @Column(name = "CreatedBy", unique = false, length = 125, nullable = true)
        public String getCreatedBy() {
            return createdBy;
        }
    
        public void setCreatedBy(String createdBy) {
            this.createdBy = createdBy;
        }
    
        @Column(name = "GLCode", unique = false, length = 11, nullable = true)
        public String getGlCode() {
            return glCode;
        }
    
        public void setGlCode(String glCode) {
            this.glCode = glCode;
        }
    
    
    }
    

    EXAMPLE

    public class SiteJsonator extends Jsonator<Site> {
    
        public SiteJsonator() {
            super(Site.class);
        }
    
    }
    
    @Controller
    @RequestMapping(value = "/sites")
    public class SitesController {
    
        @Autowired
        private SiteService siteService;
    
        @RequestMapping(value = "/", method = RequestMethod.GET, headers = "Accept=application/json")
        @ResponseBody
        public String index(ModelMap map) {
    
            SiteJsonator list  = new SiteJsonator();;
            try {
                list.convert(siteService.getAll());
                return list.results();
            }
            catch (Exception ex) {
                return list.error();
            } 
        }
    }
    

    UPDATE 2

    Here is the better Jsonator for those interested:

    https://gist.github.com/3893242

    You can pass in an "exclude" String[] and it will not include those. Plus, it has a standard "results, message, etc" that we like to pass back in our AJAX requests. Good for ExtJS.