Hibernate gives a strange ClassCast exception (using Transformers) - java

This code:
#Override
public List<FactCodeDto> getAllFactsWithoutParentsAsFactDto() {
String completeQuery = FactCodeQueries.SELECT_DTO_FROM_FACT_WITH_NO_PARENTS;
Query query = createHibernateQueryForUnmappedTypeFactDto(completeQuery);
List<FactCodeDto> factDtoList = query.list(); //line 133
return factDtoList;
}
calling this method:
private Query createHibernateQueryForUnmappedTypeFactDto(String sqlQuery) throws HibernateException {
return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(Transformers.aliasToBean(FactCodeDto.class));
}
gives me a ClassCastException -> part of the trace:
Caused by: java.lang.ClassCastException: org.bamboomy.cjr.dto.FactCodeDto cannot be cast to java.util.Map
at org.hibernate.property.access.internal.PropertyAccessMapImpl$SetterImpl.set(PropertyAccessMapImpl.java:102)
at org.hibernate.transform.AliasToBeanResultTransformer.transformTuple(AliasToBeanResultTransformer.java:78)
at org.hibernate.hql.internal.HolderInstantiator.instantiate(HolderInstantiator.java:75)
at org.hibernate.loader.custom.CustomLoader.getResultList(CustomLoader.java:435)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2423)
at org.hibernate.loader.Loader.list(Loader.java:2418)
at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:336)
at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:1898)
at org.hibernate.internal.AbstractSessionImpl.list(AbstractSessionImpl.java:318)
at org.hibernate.internal.SQLQueryImpl.list(SQLQueryImpl.java:125)
at org.bamboomy.cjr.dao.factcode.FactCodeDAOImpl.getAllFactsWithoutParentsAsFactDto(FactCodeDAOImpl.java:133)
Which is pretty strange because, indeed, if you look up the source code of Hibernate it tries to do this:
#Override
#SuppressWarnings("unchecked")
public void set(Object target, Object value, SessionFactoryImplementor factory) {
( (Map) target ).put( propertyName, value ); //line 102
}
Which doesn't make any sense...
target is of type Class and this code tries to cast it to Map,
why does it try to do that???
any pointers are more than welcome...
I'm using Hibernate 5 (and am upgrading from 3)...
edit: I also use Spring (4.2.1.RELEASE; also upgrading) which calls these methods upon deploy, any debugging pointers are most welcome as well...
edit 2: (the whole FactCodeDto class, as requested)
package org.bamboomy.cjr.dto;
import org.bamboomy.cjr.model.FactCode;
import org.bamboomy.cjr.model.FactCodeType;
import org.bamboomy.cjr.utility.FullDateUtil;
import org.bamboomy.cjr.utility.Locales;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.util.Assert;
import java.util.*;
#Getter
#Setter
#ToString
public class FactCodeDto extends TreeNodeValue {
private String cdFact;
private String cdFactSuffix;
private Boolean isSupplementCode;
private Boolean isTitleCode;
private Boolean mustBeFollowed;
private Date activeFrom;
private Date activeTo;
private Boolean isCode;
private Long idFact;
private Long idParent;
private String type;
Map<Locale, String> description = new HashMap<Locale, String>(3);
public FactCodeDto() {
}
public FactCodeDto(String prefix, String suffix) {
super();
this.cdFact = prefix;
this.cdFactSuffix = suffix;
}
public FactCodeDto(String cdFact, String cdFactSuffix, Boolean isSupplementCode, Boolean mustBeFollowed) {
super();
this.cdFact = cdFact;
this.cdFactSuffix = cdFactSuffix;
this.isSupplementCode = isSupplementCode;
this.mustBeFollowed = mustBeFollowed;
}
public FactCodeDto(String cdFact, String cdFactSuffix, Boolean isSupplementCode, Boolean mustBeFollowed, Long idFact, Long idParent, Boolean isCode, Boolean isTitleCode, Date from, Date to, Map<Locale, String> descriptions,String type) {
super();
this.cdFact = cdFact;
this.cdFactSuffix = cdFactSuffix;
this.isSupplementCode = isSupplementCode;
this.mustBeFollowed = mustBeFollowed;
this.idFact = idFact;
this.idParent = idParent;
this.isCode = isCode;
this.isTitleCode = isTitleCode;
this.activeFrom = from;
this.activeTo = to;
if (descriptions != null) {
this.description = descriptions;
}
this.type = type;
}
public FactCodeDto(FactCode fc) {
this(fc.getPrefix(), fc.getSuffix(), fc.isSupplementCode(), fc.isHasMandatorySupplCodes(), fc.getId(), fc.getParent(), fc.isActualCode(), fc.isTitleCode(), fc.getActiveFrom(), fc.getActiveTo(), fc.getAllDesc(),fc.getType().getCode());
}
public String formatCode() {
return FactCode.formatCode(cdFact, cdFactSuffix);
}
public boolean isActive() {
Date now = new Date(System.currentTimeMillis());
return FullDateUtil.isBetweenDates(now, this.activeFrom, this.activeTo);
}
public void setDescFr(String s) {
description.put(Locales.FRENCH, s);
}
public void setDescNl(String s) {
description.put(Locales.DUTCH, s);
}
public void setDescDe(String s) {
description.put(Locales.GERMAN, s);
}
/**
* public String toString() {
* StringBuilder sb = new StringBuilder();
* sb.append(getIdFact() + ": ")
* .append(getIdParent() + ": ")
* .append(" " + cdFact + cdFactSuffix + ": " + (isSupplementCode ? "NO Principal " : " Principal "))
* .append((mustBeFollowed ? " Must Be Followed " : "NOT Must Be Followed "));
* return sb.toString();
* }
*/
public Map<Locale, String> getDescription() {
return description;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
String fullCode = formatCode();
result = prime * result + ((fullCode == null) ? 0 : fullCode.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
FactCodeDto other = (FactCodeDto) obj;
return formatCode().equals(other.formatCode());
}
#Override
public boolean isChildOf(TreeNodeValue value) {
Assert.notNull(value);
boolean isChild = false;
if (value instanceof FactCodeDto) {
if (this.getIdParent() != null) {
isChild = this.getIdParent().equals(((FactCodeDto) value).getIdFact());
}
}
return isChild;
}
#Override
public boolean isBrotherOf(TreeNodeValue value) {
Assert.notNull(value);
boolean isBrother = false;
if (value instanceof FactCodeDto) {
if (this.getIdParent() != null) {
isBrother = this.getIdParent().equals(((FactCodeDto) value).getIdParent());
}
}
return isBrother;
}
#Override
public boolean isParentOf(TreeNodeValue value) {
Assert.notNull(value);
boolean isParent = false;
if (value instanceof FactCodeDto) {
isParent = this.getIdFact().equals(((FactCodeDto) value).getIdParent());
}
return isParent;
}
#Override
public int compareTo(TreeNodeValue to) {
if (to instanceof FactCodeDto) {
return formatCode().compareTo(((FactCodeDto) to).formatCode());
} else return 1;
}
public String getCode() {
return formatCode();
}
}

I found that AliasToBean has changed in Hibernate 5. For me adding getter for my field fixed the problem.

This exception occurs when the setters and getters are not mapped correctly to the column names.
Make sure you have the correct getters and setters for the query(Correct names and correct datatypes).
Read more about it here:
http://javahonk.com/java-lang-classcastexception-com-wfs-otc-datamodels-imagineexpirymodel-cannot-cast-java-util-map/

I do some investigation on this question. The problem is that Hibernate converts aliases for column names to upper case — cdFact becomesCDFACT.
Read for a more deeply explanation and workaround here:
mapping Hibernate query results to custom class?

In the end it wasn't so hard to find a solution,
I just created my own (custom) ResultTransformer and specified that in the setResultTransformer method:
private Query createHibernateQueryForUnmappedTypeFactDto(String sqlQuery) throws HibernateException {
return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(new FactCodeDtoResultTransformer());
//return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(Transformers.aliasToBean(FactCodeDto.class));
}
the code of the custom result transformer:
package org.bamboomy.cjr.dao.factcode;
import org.bamboomy.cjr.dto.FactCodeDto;
import java.util.Date;
import java.util.List;
/**
* Created by a162299 on 3-11-2015.
*/
public class FactCodeDtoResultTransformer implements org.hibernate.transform.ResultTransformer {
#Override
public Object transformTuple(Object[] objects, String[] strings) {
FactCodeDto result = new FactCodeDto();
for (int i = 0; i < objects.length; i++) {
setField(result, strings[i], objects[i]);
}
return result;
}
private void setField(FactCodeDto result, String string, Object object) {
if (string.equalsIgnoreCase("cdFact")) {
result.setCdFact((String) object);
} else if (string.equalsIgnoreCase("cdFactSuffix")) {
result.setCdFactSuffix((String) object);
} else if (string.equalsIgnoreCase("isSupplementCode")) {
result.setIsSupplementCode((Boolean) object);
} else if (string.equalsIgnoreCase("isTitleCode")) {
result.setIsTitleCode((Boolean) object);
} else if (string.equalsIgnoreCase("mustBeFollowed")) {
result.setMustBeFollowed((Boolean) object);
} else if (string.equalsIgnoreCase("activeFrom")) {
result.setActiveFrom((Date) object);
} else if (string.equalsIgnoreCase("activeTo")) {
result.setActiveTo((Date) object);
} else if (string.equalsIgnoreCase("descFr")) {
result.setDescFr((String) object);
} else if (string.equalsIgnoreCase("descNl")) {
result.setDescNl((String) object);
} else if (string.equalsIgnoreCase("descDe")) {
result.setDescDe((String) object);
} else if (string.equalsIgnoreCase("type")) {
result.setType((String) object);
} else if (string.equalsIgnoreCase("idFact")) {
result.setIdFact((Long) object);
} else if (string.equalsIgnoreCase("idParent")) {
result.setIdParent((Long) object);
} else if (string.equalsIgnoreCase("isCode")) {
result.setIsCode((Boolean) object);
} else {
throw new RuntimeException("unknown field");
}
}
#Override
public List transformList(List list) {
return list;
}
}
in hibernate 3 you could set Aliasses to queries but you can't do that anymore in hibernate 5 (correct me if I'm wrong) hence the aliasToBean is something you only can use when actually using aliasses; which I didn't, hence the exception.

Im my case :
=> write sql query and try to map result to Class List
=> Use "Transformers.aliasToBean"
=> get Error "cannot be cast to java.util.Map"
Solution :
=> just put \" before and after query aliases
ex:
"select first_name as \"firstName\" from test"
The problem is that Hibernate converts aliases for column names to upper case or lower case

I solved it by defining my own custom transformer as given below -
import org.hibernate.transform.BasicTransformerAdapter;
public class FluentHibernateResultTransformer extends BasicTransformerAdapter {
private static final long serialVersionUID = 6825154815776629666L;
private final Class<?> resultClass;
private NestedSetter[] setters;
public FluentHibernateResultTransformer(Class<?> resultClass) {
this.resultClass = resultClass;
}
#Override
public Object transformTuple(Object[] tuple, String[] aliases) {
createCachedSetters(resultClass, aliases);
Object result = ClassUtils.newInstance(resultClass);
for (int i = 0; i < aliases.length; i++) {
setters[i].set(result, tuple[i]);
}
return result;
}
private void createCachedSetters(Class<?> resultClass, String[] aliases) {
if (setters == null) {
setters = createSetters(resultClass, aliases);
}
}
private static NestedSetter[] createSetters(Class<?> resultClass, String[] aliases) {
NestedSetter[] result = new NestedSetter[aliases.length];
for (int i = 0; i < aliases.length; i++) {
result[i] = NestedSetter.create(resultClass, aliases[i]);
}
return result;
}
}
And used this way inside the repository method -
#Override
public List<WalletVO> getWalletRelatedData(WalletRequest walletRequest,
Set<String> requiredVariablesSet) throws GenericBusinessException {
String query = getWalletQuery(requiredVariablesSet);
try {
if (query != null && !query.isEmpty()) {
SQLQuery sqlQuery = mEntityManager.unwrap(Session.class).createSQLQuery(query);
return sqlQuery.setResultTransformer(new FluentHibernateResultTransformer(WalletVO.class))
.list();
}
} catch (Exception ex) {
exceptionThrower.throwDatabaseException(null, false);
}
return Collections.emptyList();
}
It worked perfectly !!!

Try putting Column names and field names both in capital letters.

This exception occurs when the class that you specified in the AliasToBeanResultTransformer does not have getter for the corresponding columns. Although the exception details from the hibernate are misleading.

Related

Creating an Hierarchy-Object with an undefined number of childs

I am currently working on a "code parser" parsing Valve Map Format (.vmf files) into a java readable Object.
In vmf files,
there are 2 types of objects: Classes and Properties.
classes have a name and can contain other classes and properties.
properties have a name and an unlimited number of values.
Therefore I created a VMFClass Object Class and a VMFProperty Object Class.
I created a List with self-created HierarchyObjects, containing the VMFClass/VMFProperty Object, an UUID and the parentUUID.
The VMFClass Object Contains 2 Lists one with sub-VMFClasses, one with properties.
My Problem is that I have no clue on how to achieve that a Class contains all of its subclasses, since I can't tell how much subclasses the subclasses have and so on...
Here is my Code (Github):
HierachyObject:
package net.minecraft.sourcecraftreloaded.utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class HierarchyObject {
private static Map<Long, Long> usedUUIDs = new HashMap<>();
private long parentUUID;
private long UUID;
private Object object;
/**
*
* #param Object
* #param parent -1 is maximum level
*/
public HierarchyObject(Object object, long parent) {
this.object = object;
this.parentUUID = parent;
while (true) {
long random = (long) (Math.random() * Long.MAX_VALUE);
if (usedUUIDs.containsKey(random)) {
this.UUID = random;
usedUUIDs.put(random, parent);
break;
}
}
}
public long getUUID() {
return UUID;
}
public long getParentUUID() {
return parentUUID;
}
public static long getParentUUIDbyUUID(long UUID) {
if (usedUUIDs.containsKey(UUID)) {
return usedUUIDs.get(UUID);
}
return -1;
}
public Object getObject() {
return object;
}
public static boolean hasChild(long UUID){
if(usedUUIDs.containsValue(UUID)){
return true;
}
if(UUID == -1){
return true;
}
return false;
}
public boolean hasChild(){
return hasChild(this.UUID);
}
public static long[] getChildUUIDs(long UUID){
if(hasChild(UUID)){
List<Long> cUUIDs = new ArrayList<>();
for(int i = 0; i < usedUUIDs.size(); i++){
for (Map.Entry<Long, Long> e : usedUUIDs.entrySet()) {
if(e.getValue().longValue() == UUID){
cUUIDs.add(e.getKey());
}
}
}
return ListUtils.toPrimitivebyList(cUUIDs);
}
return null;
}
}
VMFProperty:
package net.minecraft.sourcecraftreloaded.source;
public class VMFProperty{
private String name;
private String[] values;
public VMFProperty(String name, String... values) {
this.name = name;
this.values = values;
}
public String getName() {
return name;
}
public String[] getValues() {
return values;
}
#Override
public boolean equals(Object paramObject){
if(paramObject instanceof VMFProperty){
return ((VMFProperty)paramObject).name.equals(this.name) && ((VMFProperty)paramObject).values.equals(this.values);
}
return false;
}
}
VMFClass:
package net.minecraft.sourcecraftreloaded.source;
import java.util.List;
public class VMFClass{
private List<VMFClass> classes;
private List<VMFProperty> properties;
private String name;
public VMFClass(String name, List<VMFClass> classes, List<VMFProperty> properties) {
this.name = name;
this.classes = classes;
this.properties = properties;
}
public String getName() {
return name;
}
public List<VMFClass> getClasses() {
return classes;
}
public List<VMFProperty> getProperties() {
return properties;
}
public void add(VMFClass vmfclass) {
classes.add(vmfclass);
}
public void add(VMFProperty vmfproperty) {
properties.add(vmfproperty);
}
public void remove(VMFClass vmfclass) {
classes.remove(vmfclass);
}
public void remove(VMFProperty vmfproperty) {
properties.remove(vmfproperty);
}
#Override
public boolean equals(Object paramObject){
if(paramObject instanceof VMFClass){
return ((VMFClass)paramObject).properties.equals(this.properties) && ((VMFClass)paramObject).classes.equals(this.classes) && ((VMFClass)paramObject).name.equals(this.name);
}
return false;
}
}
VMFObject (the class executing all the code):
package net.minecraft.sourcecraftreloaded.source;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.sourcecraftreloaded.utils.HierarchyObject;
public class VMFObject {
private String rawfile = "";
private List<VMFClass> toplevelclasses;
private static final String INVALID_CHARS = "\\*,;<>|?=`´#'+~^°!§$%&()[].:-_";
public VMFObject(List<VMFClass> toplevelclasses) {
this.toplevelclasses = toplevelclasses;
}
public VMFObject() {
this(new ArrayList<VMFClass>());
}
public void write(File file) {
VMFWriter.write(file, rawfile);
}
public VMFObject read(File file) throws VMFParsingException {
this.rawfile = VMFReader.read(file);
parse();
return this;
}
public List<VMFClass> getClasses() {
return toplevelclasses;
}
private void parse() throws VMFParsingException {
evaluate();
get();
}
private void evaluate() throws VMFParsingException {
char[] textchars = rawfile.toCharArray();
int[] c = new int[]{0, 0, 0};
int line = 0;
int linepos = 0;
for (int i : textchars) {
linepos++;
if (textchars[i] == '\n') {
line++;
linepos = 0;
c[3] = 0;
if (c[3] % 2 != 0) {
throw new VMFParsingException("Invalid quotes on line" + line + ":" + linepos);
}
}
if (textchars[i] == '{') {
c[1]++;
}
if (textchars[i] == '}') {
c[2]++;
}
if (textchars[i] == '"') {
c[3]++;
if (c[1] - c[2] == 0) {
}
}
if (textchars[i] == '/' && textchars[i + 1] == '/') {
while (true) {
i++;
if (textchars[i] == '\n') {
break;
}
}
}
if (textchars[i] == '/' && textchars[i + 1] == ' ') {
throw new VMFParsingException("Invalid Character '/' on line" + line + ":" + linepos);
}
if (INVALID_CHARS.indexOf(textchars[i]) != -1) {
throw new VMFParsingException("Invalid Character '" + textchars[i] + "' on line" + line + ":" + linepos);
}
}
if (c[1] != c[2]) {
throw new VMFParsingException("Unbalanced brackets in vmf File");
}
}
public void add(VMFClass vmfclass) {
toplevelclasses.add(vmfclass);
}
private void get() throws VMFParsingException {
List<HierarchyObject> content = new ArrayList<>();
long curparent = -1;
String[] text = rawfile.split("\n");
for (int i = 0; i < text.length; i++) {
String line = text[i].trim();
if (line.startsWith("//")) {
continue;
} else {
byte quotec = 0;
char[] linechar = line.toCharArray();
boolean readp = false;
List<String> reads = new ArrayList<>();
byte creads = 0;
for (int y = 0; y < linechar.length; y++) {
if (linechar[y] == '/' && linechar[y + 1] == '/') {
break;
}
if (linechar[y] == '"') {
quotec++;
if (quotec % 2 == 0) {
readp = false;
creads++;
} else {
readp = true;
}
}
if (readp) {
reads.set(creads, reads.get(creads) + linechar[y]);
}
if (linechar[y] == '{') {
HierarchyObject object = new HierarchyObject(new VMFClass(line.substring(line.substring(0, y).lastIndexOf(' '), y).trim(), null, null), curparent);
content.add(object);
curparent = object.getUUID();
}
if (linechar[y] == '}') {
curparent = HierarchyObject.getParentUUIDbyUUID(curparent);
}
}
content.add(new HierarchyObject(new VMFProperty(reads.remove(0), reads.toArray(new String[reads.size()])), curparent));
}
}
buildObject(content);
}
private void buildObject(List<HierarchyObject> content) {
long curUUID = -1;
for(int i = 0; i < HierarchyObject.getChildUUIDs(curUUID).length; i++){
HierarchyObject.getChildUUIDs(curUUID);
}
//TODO implement
}
}
the //TODO part is where the Hierachy Object should get "converted" to the actual object.
Overview
It seems to me that your class layout is overcomplicated.
Let's try to simplify it...
What you have described with the VMF model is essentially a linked-list Tree.
Here's what the model looks like:
[.vmf file] (root)
/ \
_____/ \ _____
/ \
/ \
(VMFClass) (VMFClass)
/ \ / \
/ \ / \
/ \ / \
(VMFClass) (VMFProperties) (VMFClass) (VMFProperties)
/ \
/ \
/ \
(VMFClass) (VMFProperties)
What you need:
A Parser class (in your case, you have VMFObject, but lets call this class VMFParser).
The VMFClass and VMFProperty classes which you have are fine.
What you don't need:
The HierarchyObject class. The VMFParser can be the main controller and container for the hierarchy (e.g. the linked-list Tree model).
All the UUIDs (parent, child, etc.) These are just complicated things, but I see why you have them. You don't need them to track the hierarchy - Java will do this for us!!
VMFClass
public class VMFClass
{
// name of the class
private String name;
// reference back up to the parent
private VMFClass parentClass = null;
// all direct children go here
private List<VMFClass> children = new ArrayList<VMFClass>();
// I don't think you need a list of properties here since your VMFProperty class holds onto an array of properties
private VMFProperty properties;
// set the parent of this class
public void setParent (VMFClass parent)
{
this.parentClass = parent;
}
// get the direct children
public List<VMFClass> getChildren()
{
return this.children;
}
// rest of methods...
}
VMFParser
class VMFParser
{
private String rawfile = "";
// this is really the container for everything - think of it as the file shell
private VMFClass root = new VMFClass("root", null, null);
// construct yourself with the file
public VMFParser (String fileName)
{
this.rawfile = fileName;
}
public void parse ()
{
// all the parsing code goes here
read();
evaluate();
get();
// now at this point your hierarchy is built and stored in the
// root object in this class.
// Use the traverse method to go through it
}
private void get() throws VMFParsingException
{
// keep a reference to the current VMFClass parent
// starts out as root
VMFClass currParentClass = root;
// main parse loop
for (...)
{
// if you find a class
VMFClass currClass = new VMFClass(/* params here */);
// add this class to the parent
currParentClass.add(currClass);
// set the parent of this class
currClass.setParent(currParentClass);
// if you find a property
// parse and add all the properties to the property
VMFProperty property = new VMFProperty (/* value params here */);
// attach this property to the last VMF class that got parsed
currClass.setPoperties(property);
// If you nest deeper into classes, then the parent becomes the current class
currParentClass = currClass;
// If you go back out of a class
currParentClass = currClass.getParent();
}
}
// Traverse the hierarchy
public void traverse ()
{
traverseTree(root);
}
private void traverseTree (VMFClass root)
{
System.out.println("Class Name: " + root.getName());
// print out any properties
VMFProperty prop = root.getProperty();
if (prop != null)
{
System.out.println("Property Name: " + prop.getName());
String [] props = prop.getValues();
for (String s: props)
{
System.out.println("Value: " + s);
}
}
// get all child classes
List<VMFClass> children = root.getChildren();
for (VMFClass c: children)
{
traverseTree(c);
}
}
}
Client Code
Example
public static void main(String[] args)
{
VMFParser vmfParser = null;
try
{
vmfParser = new VMFParser("myFile.vmf");
vmfParser.parse();
// access the vmfParser for the hierarchy
vmfParser.traverse();
}
catch (VMFParsingException vpe)
{
// do something here
vpe.printStackTrace();
}
finally
{
// clean up...
}
}
If you are just looking to find all sub classes of particular class or interface , this might help you,
How can I get a list of all the implementations of an interface programmatically in Java?

How to write JUnit Test Case for ArrayList Object?

Here is my First Class AdminPostlCode. Contains some Strings and it's getters and Setters.
package org.sanket.zivameDataBase.adminPostalCode.model;
public class AdminPostalCode {
private String entity_id1;
private String postal_code1;
private String city1;
private String state1;
private String country1;
private String days_to_deliver1;
private String cod1;
private String pg1;
private String rpu1;
private String updated_by1;
private String updated_at1;
private String cod_couriername1;
private String pg_couriername1;
private String rto_couriername1;
public AdminPostalCode(){}
public AdminPostalCode(String entity_id1, String postal_code1,
String city1, String state1, String country1,
String days_to_deliver1, String cod1, String pg1, String rpu1,
String updated_by1, String updated_at1, String cod_couriername1,
String pg_couriername1, String rto_couriername1) {
super();
this.entity_id1 = entity_id1;
this.postal_code1 = postal_code1;
this.city1 = city1;
this.state1 = state1;
this.country1 = country1;
this.days_to_deliver1 = days_to_deliver1;
this.cod1 = cod1;
this.pg1 = pg1;
this.rpu1 = rpu1;
this.updated_by1 = updated_by1;
this.updated_at1 = updated_at1;
this.cod_couriername1 = cod_couriername1;
this.pg_couriername1 = pg_couriername1;
this.rto_couriername1 = rto_couriername1;
}
public String getEntity_id1() {
return entity_id1;
}
public void setEntity_id1(String entity_id1) {
this.entity_id1 = entity_id1;
}
public String getPostal_code1() {
return postal_code1;
}
public void setPostal_code1(String postal_code1) {
this.postal_code1 = postal_code1;
}
public String getCity1() {
return city1;
}
public void setCity1(String city1) {
this.city1 = city1;
}
public String getState1() {
return state1;
}
public void setState1(String state1) {
this.state1 = state1;
}
public String getCountry1() {
return country1;
}
public void setCountry1(String country1) {
this.country1 = country1;
}
public String getDays_to_deliver1() {
return days_to_deliver1;
}
public void setDays_to_deliver1(String days_to_deliver1) {
this.days_to_deliver1 = days_to_deliver1;
}
public String getCod1() {
return cod1;
}
public void setCod1(String cod1) {
this.cod1 = cod1;
}
public String getPg1() {
return pg1;
}
public void setPg1(String pg1) {
this.pg1 = pg1;
}
public String getRpu1() {
return rpu1;
}
public void setRpu1(String rpu1) {
this.rpu1 = rpu1;
}
public String getUpdated_by1() {
return updated_by1;
}
public void setUpdated_by1(String updated_by1) {
this.updated_by1 = updated_by1;
}
public String getUpdated_at1() {
return updated_at1;
}
public void setUpdated_at1(String updated_at1) {
this.updated_at1 = updated_at1;
}
public String getCod_couriername1() {
return cod_couriername1;
}
public void setCod_couriername1(String cod_couriername1) {
this.cod_couriername1 = cod_couriername1;
}
public String getPg_couriername1() {
return pg_couriername1;
}
public void setPg_couriername1(String pg_couriername1) {
this.pg_couriername1 = pg_couriername1;
}
public String getRto_couriername1() {
return rto_couriername1;
}
public void setRto_couriername1(String rto_couriername1) {
this.rto_couriername1 = rto_couriername1;
}
}
Here is My Database connection Class
package org.sanket.zivameDataBase.adminPostalCode.DataBase;
import java.sql.Connection;
import java.sql.DriverManager;
public class DataBaseConnection {
public Connection getConnection() throws Exception
{
try
{
String connectionURL = "jdbc:mysql://localhost:3306/zdb";
Connection connection = null;
Class.forName("com.mysql.jdbc.Driver").newInstance();
connection = DriverManager.getConnection(connectionURL, "root", "root");
return connection;
} catch (Exception e)
{
throw e;
}
}
}
Here is my access class.
package org.sanket.zivameDataBase.adminPostalCode.DataBase;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.sanket.zivameDataBase.adminPostalCode.model.AdminPostalCode;
public class Access {
public List<AdminPostalCode> getAdminPostalCode(int code,Connection con) throws SQLException
{
List<AdminPostalCode> adminDetail = new ArrayList<AdminPostalCode>();
PreparedStatement stmt = con.prepareStatement("select * from admin_postalcode where postal_code ="+code+"");
ResultSet resultSet = stmt.executeQuery();
//System.out.println(resultSet);
try
{
while (resultSet.next())
{
AdminPostalCode adminPostalCode = new AdminPostalCode();
adminPostalCode.setEntity_id1(resultSet.getString("entity_id"));
adminPostalCode.setPostal_code1(resultSet.getString("postal_code"));
adminPostalCode.setCity1(resultSet.getString("city"));
adminPostalCode.setState1(resultSet.getString("state"));
adminPostalCode.setCountry1(resultSet.getString("country"));
adminPostalCode.setDays_to_deliver1(resultSet.getString("days_to_deliver"));
adminPostalCode.setCod1(resultSet.getString("cod"));
adminPostalCode.setPg1(resultSet.getString("pg"));
adminPostalCode.setRpu1(resultSet.getString("rpu"));
adminPostalCode.setUpdated_by1(resultSet.getString("updated_by"));
adminPostalCode.setUpdated_at1(resultSet.getString("updated_at"));
adminPostalCode.setCod_couriername1(resultSet.getString("cod_couriername"));
adminPostalCode.setPg_couriername1(resultSet.getString("pg_couriername"));
adminPostalCode.setRto_couriername1(resultSet.getString("rto_couriername"));
adminDetail.add(adminPostalCode);
}
}catch (SQLException e)
{
e.printStackTrace();
}
return adminDetail ;
}
}
Now I want to write JUnit test case for Above code. And I tried in following way. But it is not working Please Help me in writing JUnit Test case. Remaining Everything is working fine.
package adminPostalCode;
import static org.junit.Assert.*;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.sanket.zivameDataBase.adminPostalCode.DataBase.Access;
import org.sanket.zivameDataBase.adminPostalCode.DataBase.DataBaseConnection;
import org.sanket.zivameDataBase.adminPostalCode.model.AdminPostalCode;
public class SampleTest {
List<AdminPostalCode> detailsActual = new ArrayList<AdminPostalCode>();
List<AdminPostalCode> detailsExpected = new ArrayList<AdminPostalCode>();
boolean abc;
AdminPostalCode adminPoCo = new AdminPostalCode();
public SampleTest()
{
adminPoCo.setCity1("WEST CHAMPARAN");
adminPoCo.setCod1("0");
adminPoCo.setCod_couriername1("NO SERVICE");
adminPoCo.setDays_to_deliver1("11");
adminPoCo.setEntity_id1("19625");
adminPoCo.setPg1("1");
adminPoCo.setPg_couriername1("INDIA POST");
adminPoCo.setPostal_code1("845106");
adminPoCo.setRpu1("0");
adminPoCo.setRto_couriername1("NO SERVICE");
adminPoCo.setState1("BIHAR");
adminPoCo.setUpdated_by1("panindra#milastar.in");
adminPoCo.setUpdated_at1("2015-03-19 19:30:22.0");
adminPoCo.setCountry1("IN");
detailsExpected.add(adminPoCo);
}
#Test
public void test() throws Exception {
//fail("Not yet implemented");
DataBaseConnection db = new DataBaseConnection();
Connection con = db.getConnection();
Access access = new Access();
detailsActual =access.getAdminPostalCode(845106, con);
abc = (detailsActual.equals(detailsExpected)) ;
System.out.println(abc);
}
}
use assertXxx in junit instead of System.out. junit is used to automate your test and find potential problems in your code and provide useful information about them. junit will help much less if you use System.out.
if you use junit to write a unit test, you should not connect the 'real' database, you should use some mock framework such as mockito to mock an Access object.
if you want write integration test using junit, you should use some specific junit extension framework like dbunit.
You have to use assertEquals for testing
assertEquals(detailsActual,detailsExpected);
if you are comparing arrayList object, you have to convert them to array than you can use assertArrayEquals.
It seems what you are looking for is away to compare 2 objects of type ArrayList.
The answer to this is by overriding equals method.
Add the below code to your AdminPostalCode POJO class.
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final AdminPostalCode other = (AdminPostalCode) obj;
if (city1 == null) {
if (other.city1 != null)
return false;
} else if (!city1.equals(other.city1))
return false;
if (cod1 == null) {
if (other.cod1 != null)
return false;
} else if (!cod1.equals(other.cod1))
return false;
if (cod_couriername1 == null) {
if (other.cod_couriername1 != null)
return false;
} else if (!cod_couriername1.equals(other.cod_couriername1))
return false;
if (country1 == null) {
if (other.country1 != null)
return false;
} else if (!country1.equals(other.country1))
return false;
if (days_to_deliver1 == null) {
if (other.days_to_deliver1 != null)
return false;
} else if (!days_to_deliver1.equals(other.days_to_deliver1))
return false;
if (entity_id1 == null) {
if (other.entity_id1 != null)
return false;
} else if (!entity_id1.equals(other.entity_id1))
return false;
if (pg1 == null) {
if (other.pg1 != null)
return false;
} else if (!pg1.equals(other.pg1))
return false;
if (pg_couriername1 == null) {
if (other.pg_couriername1 != null)
return false;
} else if (!pg_couriername1.equals(other.pg_couriername1))
return false;
if (postal_code1 == null) {
if (other.postal_code1 != null)
return false;
} else if (!postal_code1.equals(other.postal_code1))
return false;
if (rpu1 == null) {
if (other.rpu1 != null)
return false;
} else if (!rpu1.equals(other.rpu1))
return false;
if (rto_couriername1 == null) {
if (other.rto_couriername1 != null)
return false;
} else if (!rto_couriername1.equals(other.rto_couriername1))
return false;
if (state1 == null) {
if (other.state1 != null)
return false;
} else if (!state1.equals(other.state1))
return false;
if (updated_at1 == null) {
if (other.updated_at1 != null)
return false;
} else if (!updated_at1.equals(other.updated_at1))
return false;
if (updated_by1 == null) {
if (other.updated_by1 != null)
return false;
} else if (!updated_by1.equals(other.updated_by1))
return false;
return true;
}
The above method will help you compare the 2 Actual and Expected objects.
Though, a correct JUnit will make use of assertEquals, verify, etc to validate results
Your AdminPostalCode class should implement boolean equals(Object other) and also int hashCode(). Implementing these methods will guarantee that custom objects, like your AdminPostalCode class, will be able to perform checks on certain fields. assertEquals(detailsActual, detailsExpected) f.e. invokes this method internally. By default equals(...) compares objects on their memory address instead of the content. That's why you should overwrite these two methods.
If you don't want to overwrite these methods (for whatever reason), you also have the possibility to implement custom Hamcrest matchers which will perform the equality check. You are then able to utilize this matcher like this: assertThat(detailsActual, containsAdminPostalCodes(detailsExpected)); where containsAdminPostalCodes(...) is your custom Hamcrest matcher which takes a List of AdminPostalCode as input. Inside this Hamcrest matcher you will need to compare the fields of the AdminPostalCode instances of the actual list with the one provided in the expected list.
Hamcrest comes already with quite a lot of matchers. So check if there are already any available that suits your need, though some may rely on a correct implementation of equals(...) and hashCode().
Also, as #walsh has correctly pointed out, you should not call a database in your unit-test directly but instead use mocked objects (Mockito, PowerMock, ...). If you write integration tests (our company f.e. prefers integration tests over unit-tests), try to refactor the initialization and tear-down code for your database into JUnit rules

Json array and retrofit

I've this kind of json response:
{
error: false
stats: {
punti: 150
punti2: 200
}-
}
I created a StatsReceiver class:
public class StatsReceiver {
Boolean error;
Stats stat;
public Boolean isError() {
if (error == null)
return true;
else
return error;
}
public int getPunti() {
if (stat == null)
return -1;
else
return stat.getPunti();
}
private class Stats {
private int punti = 0;
public int getPunti() {
return punti;
}
public void setPunti(int punti) {
this.punti = punti;
}
public int getPunti2() {
return punti2;
}
public void setPunti2(int punti2) {
this.punti2 = punti2;
}
private int punti2 = 0;
public Stats(int punti, int punti2) {
this.punti = punti;
this.punti2 = punti2;
}
}
}
Next:
#GET("/v1/stats")
void stats(#Header("Auth") String code,
Callback<StatsReceiver> object);
Now when I do:
apiServiceUsers.stats(apiKey, new Callback<StatsReceiver>() {
#Override
public void success(StatsReceiver statsReceiver, Response response) {
if (statsReceiver.isError()) {
Toast.makeText(this, "Error", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, statsReceiver.getPunti(), Toast.LENGTH_LONG).show();
}
}
Error is false as expected, but getPunti() return always -1, so stat object is always null.
What's wrong?
P.S in the Log console, there is:
{"error":false,"stats":{"punti":150,"punti2":200}}
In your JSON example the key is stats; but in your Java class the member variable is called stat. For Gson to work, these must be either exactly the same, or you must use #SerializedName to tell Gson which JSON key corresponds to which variable:
#SerializedName("stats")
Stats statOrSomethingElseEntirely;

Get single field from JSON using Jackson

Given an arbitrary JSON I would like to get value of a single field contentType. How to do it with Jackson?
{
contentType: "foo",
fooField1: ...
}
{
contentType: "bar",
barArray: [...]
}
Related
How to find specified name and its value in JSON-string from Java? (GSON)
Using gson to deserialize specific JSON field of an object (GSON)
The Jackson Way
Considering that you don't have a POJO describing your data structure, you could simply do:
final String json = "{\"contentType\": \"foo\", \"fooField1\": ... }";
final ObjectNode node = new ObjectMapper().readValue(json, ObjectNode.class);
// ^
// actually, try and *reuse* a single instance of ObjectMapper
if (node.has("contentType")) {
System.out.println("contentType: " + node.get("contentType"));
}
Addressing concerns in the comments section
If, however, you wish to not consume the entire source String, but simply access a specific property whose path you know, you'll have to write it yourself, leveraging a Tokeniser.
Actually, it's the weekend and I got time on my hands, so I could give you a head start: here's a basic one! It can run in strict mode and spew out sensible error messages, or be lenient and return Optional.empty when the request couldn't be fulfilled.
public static class JSONPath {
protected static final JsonFactory JSON_FACTORY = new JsonFactory();
private final List<JSONKey> keys;
public JSONPath(final String from) {
this.keys = Arrays.stream((from.startsWith("[") ? from : String.valueOf("." + from))
.split("(?=\\[|\\]|\\.)"))
.filter(x -> !"]".equals(x))
.map(JSONKey::new)
.collect(Collectors.toList());
}
public Optional<String> getWithin(final String json) throws IOException {
return this.getWithin(json, false);
}
public Optional<String> getWithin(final String json, final boolean strict) throws IOException {
try (final InputStream stream = new StringInputStream(json)) {
return this.getWithin(stream, strict);
}
}
public Optional<String> getWithin(final InputStream json) throws IOException {
return this.getWithin(json, false);
}
public Optional<String> getWithin(final InputStream json, final boolean strict) throws IOException {
return getValueAt(JSON_FACTORY.createParser(json), 0, strict);
}
protected Optional<String> getValueAt(final JsonParser parser, final int idx, final boolean strict) throws IOException {
try {
if (parser.isClosed()) {
return Optional.empty();
}
if (idx >= this.keys.size()) {
parser.nextToken();
if (null == parser.getValueAsString()) {
throw new JSONPathException("The selected node is not a leaf");
}
return Optional.of(parser.getValueAsString());
}
this.keys.get(idx).advanceCursor(parser);
return getValueAt(parser, idx + 1, strict);
} catch (final JSONPathException e) {
if (strict) {
throw (null == e.getCause() ? new JSONPathException(e.getMessage() + String.format(", at path: '%s'", this.toString(idx)), e) : e);
}
return Optional.empty();
}
}
#Override
public String toString() {
return ((Function<String, String>) x -> x.startsWith(".") ? x.substring(1) : x)
.apply(this.keys.stream().map(JSONKey::toString).collect(Collectors.joining()));
}
private String toString(final int idx) {
return ((Function<String, String>) x -> x.startsWith(".") ? x.substring(1) : x)
.apply(this.keys.subList(0, idx).stream().map(JSONKey::toString).collect(Collectors.joining()));
}
#SuppressWarnings("serial")
public static class JSONPathException extends RuntimeException {
public JSONPathException() {
super();
}
public JSONPathException(final String message) {
super(message);
}
public JSONPathException(final String message, final Throwable cause) {
super(message, cause);
}
public JSONPathException(final Throwable cause) {
super(cause);
}
}
private static class JSONKey {
private final String key;
private final JsonToken startToken;
public JSONKey(final String str) {
this(str.substring(1), str.startsWith("[") ? JsonToken.START_ARRAY : JsonToken.START_OBJECT);
}
private JSONKey(final String key, final JsonToken startToken) {
this.key = key;
this.startToken = startToken;
}
/**
* Advances the cursor until finding the current {#link JSONKey}, or
* having consumed the entirety of the current JSON Object or Array.
*/
public void advanceCursor(final JsonParser parser) throws IOException {
final JsonToken token = parser.nextToken();
if (!this.startToken.equals(token)) {
throw new JSONPathException(String.format("Expected token of type '%s', got: '%s'", this.startToken, token));
}
if (JsonToken.START_ARRAY.equals(this.startToken)) {
// Moving cursor within a JSON Array
for (int i = 0; i != Integer.valueOf(this.key).intValue(); i++) {
JSONKey.skipToNext(parser);
}
} else {
// Moving cursor in a JSON Object
String name;
for (parser.nextToken(), name = parser.getCurrentName(); !this.key.equals(name); parser.nextToken(), name = parser.getCurrentName()) {
JSONKey.skipToNext(parser);
}
}
}
/**
* Advances the cursor to the next entry in the current JSON Object
* or Array.
*/
private static void skipToNext(final JsonParser parser) throws IOException {
final JsonToken token = parser.nextToken();
if (JsonToken.START_ARRAY.equals(token) || JsonToken.START_OBJECT.equals(token) || JsonToken.FIELD_NAME.equals(token)) {
skipToNextImpl(parser, 1);
} else if (JsonToken.END_ARRAY.equals(token) || JsonToken.END_OBJECT.equals(token)) {
throw new JSONPathException("Could not find requested key");
}
}
/**
* Recursively consumes whatever is next until getting back to the
* same depth level.
*/
private static void skipToNextImpl(final JsonParser parser, final int depth) throws IOException {
if (depth == 0) {
return;
}
final JsonToken token = parser.nextToken();
if (JsonToken.START_ARRAY.equals(token) || JsonToken.START_OBJECT.equals(token) || JsonToken.FIELD_NAME.equals(token)) {
skipToNextImpl(parser, depth + 1);
} else {
skipToNextImpl(parser, depth - 1);
}
}
#Override
public String toString() {
return String.format(this.startToken.equals(JsonToken.START_ARRAY) ? "[%s]" : ".%s", this.key);
}
}
}
Assuming the following JSON content:
{
"people": [{
"name": "Eric",
"age": 28
}, {
"name": "Karin",
"age": 26
}],
"company": {
"name": "Elm Farm",
"address": "3756 Preston Street Wichita, KS 67213",
"phone": "857-778-1265"
}
}
... you could use my JSONPath class as follows:
final String json = "{\"people\":[],\"company\":{}}"; // refer to JSON above
System.out.println(new JSONPath("people[0].name").getWithin(json)); // Optional[Eric]
System.out.println(new JSONPath("people[1].name").getWithin(json)); // Optional[Karin]
System.out.println(new JSONPath("people[2].name").getWithin(json)); // Optional.empty
System.out.println(new JSONPath("people[0].age").getWithin(json)); // Optional[28]
System.out.println(new JSONPath("company").getWithin(json)); // Optional.empty
System.out.println(new JSONPath("company.name").getWithin(json)); // Optional[Elm Farm]
Keep in mind that it's basic. It doesn't coerce data types (every value it returns is a String) and only returns leaf nodes.
Actual test case
It handles InputStreams, so you can test it against some giant JSON document and see that it's much faster than it would take your browser to download and display its contents:
System.out.println(new JSONPath("info.contact.email")
.getWithin(new URL("http://test-api.rescuegroups.org/v5/public/swagger.php").openStream()));
// Optional[support#rescuegroups.org]
Quick test
Note I'm not re-using any already existing JSONPath or ObjectMapper so the results are inaccurate -- this is just a very rough comparison anyways:
public static Long time(final Callable<?> r) throws Exception {
final long start = System.currentTimeMillis();
r.call();
return Long.valueOf(System.currentTimeMillis() - start);
}
public static void main(final String[] args) throws Exception {
final URL url = new URL("http://test-api.rescuegroups.org/v5/public/swagger.php");
System.out.println(String.format( "%dms to get 'info.contact.email' with JSONPath",
time(() -> new JSONPath("info.contact.email").getWithin(url.openStream()))));
System.out.println(String.format( "%dms to just download the entire document otherwise",
time(() -> new Scanner(url.openStream()).useDelimiter("\\A").next())));
System.out.println(String.format( "%dms to bluntly map it entirely with Jackson and access a specific field",
time(() -> new ObjectMapper()
.readValue(url.openStream(), ObjectNode.class)
.get("info").get("contact").get("email"))));
}
378ms to get 'info.contact.email' with JSONPath
756ms to just download the entire document otherwise
896ms to bluntly map it entirely with Jackson and access a specific field
Just want to update for 2019. I found the following easiest to impl:
//json can be file or String
JsonNode parent= new ObjectMapper().readTree(json);
String content = parent.path("contentType").asText();
I would suggest to use path instead of get as get throws a NPE, where path returns with a default 0 or "", which is safer to work with if setting up the parsing correctly for 1st time.
My $0.02
If you are using JSON jars in your application then the following code snippet is useful:
String json = "{\"contentType\": \"foo\", \"fooField1\": ... }";
JSONObject jsonObject = new JSONObject(json);
System.out.println(jsonObject.getString("contentType"));
and if you are using Gson jars then the same code will look like following:
Gson gson = new GsonBuilder().create();
Map jsonMap = gson.fromJson(json, Map.class);
System.out.println(jsonMap.get("contentType"));
Another way is:
String json = "{\"contentType\": \"foo\", \"fooField1\": ... }";
JsonNode parent= new ObjectMapper().readTree(json);
String content = parent.get("contentType").asText();
I faced this issue when I decided to use Jackson as the json library for a project I worked on; mainly for its speed. I was already used to using org.json and Gson for my projects.
I quickly found out though that many tasks that were trivial in org.json and Gson were not so straightforward in Jackson
So I wrote the following classes to make things easier for me.
The classes below will allow you to use Jackson as easily as you would the simple org.json library, while still retaining the power and speed of Jackson
I wrote the whole thing in a few hours, so feel free to debug and suit the code to your own purposes.
Note that JSONObject/JSONArray below will do exactly what the OP wants.
The first is JSONObject which has similar methods to org.json.JSONObject; but at heart runs Jackson code to build JSON and parse json strings.
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* #author GBEMIRO JIBOYE <gbenroscience#gmail.com>
*/
public class JSONObject {
ObjectNode parseNode;
public JSONObject() {
this.parseNode = JsonNodeFactory.instance.objectNode(); // initializing
}
public JSONObject(String json) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
try {
this.parseNode = mapper.readValue(json, ObjectNode.class);
} catch (JsonProcessingException ex) {
Logger.getLogger(JSONObject.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void put(String key, String value) {
parseNode.put("key", value); // building
}
public void put(String key, boolean value) {
parseNode.put("key", value); // building
}
public void put(String key, int value) {
parseNode.put("key", value); // building
}
public void put(String key, short value) {
parseNode.put("key", value); // building
}
public void put(String key, float value) {
parseNode.put("key", value); // building
}
public void put(String key, long value) {
parseNode.put("key", value); // building
}
public void put(String key, double value) {
parseNode.put("key", value); // building
}
public void put(String key, byte[] value) {
parseNode.put("key", value); // building
}
public void put(String key, BigInteger value) {
parseNode.put("key", value); // building
}
public void put(String key, BigDecimal value) {
parseNode.put("key", value); // building
}
public void put(String key, Object[] value) {
ArrayNode anode = parseNode.putArray(key);
for (Object o : value) {
anode.addPOJO(o); // building
}
}
public void put(String key, JSONObject value) {
parseNode.set(key, value.parseNode);
}
public void put(String key, Object value) {
parseNode.putPOJO(key, value);
}
public static class Parser<T> {
public T decode(String json, Class clazz) {
try {
return new Converter<T>().fromJsonString(json, clazz);
} catch (IOException ex) {
Logger.getLogger(JSONObject.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
}
public int optInt(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null ? nod.asInt(0) : 0;
}
return 0;
}
public long optLong(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null ? nod.asLong(0) : 0;
}
return 0;
}
public double optDouble(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null ? nod.asDouble(0) : 0;
}
return 0;
}
public boolean optBoolean(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null ? nod.asBoolean(false) : false;
}
return false;
}
public double optFloat(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null && nod.isFloat() ? nod.floatValue() : 0;
}
return 0;
}
public short optShort(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null && nod.isShort() ? nod.shortValue() : 0;
}
return 0;
}
public byte optByte(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null && nod.isShort() ? (byte) nod.asInt(0) : 0;
}
return 0;
}
public JSONObject optJSONObject(String key) {
if (parseNode != null) {
if (parseNode.has(key)) {
ObjectNode nod = parseNode.with(key);
JSONObject obj = new JSONObject();
obj.parseNode = nod;
return obj;
}
}
return new JSONObject();
}
public JSONArray optJSONArray(String key) {
if (parseNode != null) {
if (parseNode.has(key)) {
ArrayNode nod = parseNode.withArray(key);
JSONArray obj = new JSONArray();
if (nod != null) {
obj.parseNode = nod;
return obj;
}
}
}
return new JSONArray();
}
public String optString(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return parseNode != null && nod.isTextual() ? nod.asText("") : "";
}
return "";
}
#Override
public String toString() {
return parseNode.toString();
}
public String toCuteString() {
return parseNode.toPrettyString();
}
}
Here is the code for the JSONArray equivalent that works like org.json.JSONArray; but uses Jackson code.
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.math.BigDecimal;
import java.math.BigInteger;
/**
*
* #author GBEMIRO JIBOYE <gbenroscience#gmail.com>
*/
public class JSONArray {
protected ArrayNode parseNode;
public JSONArray() {
this.parseNode = JsonNodeFactory.instance.arrayNode(); // initializing
}
public JSONArray(String json) throws JsonProcessingException{
ObjectMapper mapper = new ObjectMapper();
this.parseNode = mapper.readValue(json, ArrayNode.class);
}
public void putByte(byte val) {
parseNode.add(val);
}
public void putShort(short val) {
parseNode.add(val);
}
public void put(int val) {
parseNode.add(val);
}
public void put(long val) {
parseNode.add(val);
}
public void pu(float val) {
parseNode.add(val);
}
public void put(double val) {
parseNode.add(val);
}
public void put(String val) {
parseNode.add(val);
}
public void put(byte[] val) {
parseNode.add(val);
}
public void put(BigDecimal val) {
parseNode.add(val);
}
public void put(BigInteger val) {
parseNode.add(val);
}
public void put(Object val) {
parseNode.addPOJO(val);
}
public void put(int index, JSONArray value) {
parseNode.set(index, value.parseNode);
}
public void put(int index, JSONObject value) {
parseNode.set(index, value.parseNode);
}
public String optString(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null ? nod.asText("") : "";
}
return "";
}
public int optInt(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null ? nod.asInt(0) : 0;
}
return 0;
}
public long optLong(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null ? nod.asLong(0) : 0;
}
return 0;
}
public double optDouble(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null ? nod.asDouble(0) : 0;
}
return 0;
}
public boolean optBoolean(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null ? nod.asBoolean(false) : false;
}
return false;
}
public double optFloat(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null && nod.isFloat() ? nod.floatValue() : 0;
}
return 0;
}
public short optShort(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null && nod.isShort() ? nod.shortValue() : 0;
}
return 0;
}
public byte optByte(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null && nod.isShort() ? (byte) nod.asInt(0) : 0;
}
return 0;
}
public JSONObject optJSONObject(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
if(nod != null){
if(nod.isObject()){
ObjectNode obn = (ObjectNode) nod;
JSONObject obj = new JSONObject();
obj.parseNode = obn;
return obj;
}
}
}
return new JSONObject();
}
public JSONArray optJSONArray(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
if(nod != null){
if(nod.isArray()){
ArrayNode anode = (ArrayNode) nod;
JSONArray obj = new JSONArray();
obj.parseNode = anode;
return obj;
}
}
}
return new JSONArray();
}
#Override
public String toString() {
return parseNode.toString();
}
public String toCuteString() {
return parseNode.toPrettyString();
}
}
Finally for a one size-fits-all-most-likely for encoding and decoding your Java classes to JSON, I added this simple class:
/**
*
* #author GBEMIRO JIBOYE <gbenroscience#gmail.com>
*/
public class Converter<T> {
// Serialize/deserialize helpers
private Class clazz;
public Converter() {}
public T fromJsonString(String json , Class clazz) throws IOException {
this.clazz = clazz;
return getObjectReader().readValue(json);
}
public String toJsonString(T obj) throws JsonProcessingException {
this.clazz = obj.getClass();
return getObjectWriter().writeValueAsString(obj);
}
private ObjectReader requestReader;
private ObjectWriter requestWriter;
private void instantiateMapper() {
ObjectMapper mapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
requestReader = mapper.readerFor(clazz);
requestWriter = mapper.writerFor(clazz);
}
private ObjectReader getObjectReader() {
if (requestReader == null) {
instantiateMapper();
}
return requestReader;
}
private ObjectWriter getObjectWriter() {
if (requestWriter == null) {
instantiateMapper();
}
return requestWriter;
}
}
Now to taste(test) the sauce(code), use the following methods:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* #author GBEMIRO JIBOYE <gbenroscience#gmail.com>
*/
public class SimplerJacksonTest {
static class Credentials {
private String userName;
private String uid;
private String password;
private long createdAt;
public Credentials() {
}
public Credentials(String userName, String uid, String password, long createdAt) {
this.userName = userName;
this.uid = uid;
this.password = password;
this.createdAt = createdAt;
}
#JsonProperty("userName")
public String getUserName() {
return userName;
}
#JsonProperty("userName")
public void setUserName(String userName) {
this.userName = userName;
}
#JsonProperty("uid")
public String getUid() {
return uid;
}
#JsonProperty("uid")
public void setUid(String uid) {
this.uid = uid;
}
#JsonProperty("password")
public String getPassword() {
return password;
}
#JsonProperty("password")
public void setPassword(String password) {
this.password = password;
}
#JsonProperty("createdAt")
public long getCreatedAt() {
return createdAt;
}
#JsonProperty("createdAt")
public void setCreatedAt(long createdAt) {
this.createdAt = createdAt;
}
public String encode() {
try {
return new Converter<Credentials>().toJsonString(this);
} catch (JsonProcessingException ex) {
Logger.getLogger(Credentials.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
public Credentials decode(String jsonData) {
try {
return new Converter<Credentials>().fromJsonString(jsonData, Credentials.class);
} catch (Exception ex) {
Logger.getLogger(Converter.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
}
public static JSONObject testJSONObjectBuild() {
JSONObject obj = new JSONObject();
Credentials cred = new Credentials("Adesina", "01eab26bwkwjbak2vngxh9y3q6", "xxxxxx1234", System.currentTimeMillis());
String arr[] = new String[]{"Boy", "Girl", "Man", "Woman"};
int nums[] = new int[]{0, 1, 2, 3, 4, 5};
obj.put("creds", cred);
obj.put("pronouns", arr);
obj.put("creds", cred);
obj.put("nums", nums);
System.out.println("json-coding: " + obj.toCuteString());
return obj;
}
public static void testJSONObjectParse(String json) {
JSONObject obj;
try {
obj = new JSONObject(json);
JSONObject credsObj = obj.optJSONObject("creds");
String userName = credsObj.optString("userName");
String uid = credsObj.optString("uid");
String password = credsObj.optString("password");
long createdAt = credsObj.optLong("createdAt");
System.out.println("<<---Parse Results--->>");
System.out.println("userName = " + userName);
System.out.println("uid = " + uid);
System.out.println("password = " + password);
System.out.println("createdAt = " + createdAt);
} catch (JsonProcessingException ex) {
Logger.getLogger(JSONObject.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static JSONArray testJSONArrayBuild() {
JSONArray array = new JSONArray();
array.put(new Credentials("Lawani", "001uadywdbs", "ampouehehu", System.currentTimeMillis()));
array.put("12");
array.put(98);
array.put(Math.PI);
array.put("Good scores!");
System.out.println("See the built array: "+array.toCuteString());
return array;
}
public static void testJSONArrayParse(String json) {
try {
JSONArray array = new JSONArray(json);
JSONObject credsObj = array.optJSONObject(0);
//Parse credentials in index 0
String userName = credsObj.optString("userName");
String uid = credsObj.optString("uid");
String password = credsObj.optString("password");
long createdAt = credsObj.optLong("createdAt");
//Now return to the main array and parse other entries
String twelve = array.optString(1);
int ninety = array.optInt(2);
double pi = array.optDouble(3);
String scoreNews = array.optString(4);
System.out.println("Parse Results");
System.out.println("userName = " + userName);
System.out.println("uid = " + uid);
System.out.println("password = " + password);
System.out.println("createdAt = " + createdAt);
System.out.println("Parse Results");
System.out.println("index 1 = " + twelve);
System.out.println("index 2 = " + ninety);
System.out.println("index 3 = " + pi);
System.out.println("index 4 = " + scoreNews);
} catch (JsonProcessingException ex) {
Logger.getLogger(JSONObject.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static String testCredentialsEncode(){
Credentials cred = new Credentials("Olaoluwa", "01eab26bwkwjbak2vngxh9y3q6", "xxxxxx1234", System.currentTimeMillis());
String encoded = cred.encode();
System.out.println("encoded credentials = "+encoded);
return encoded;
}
public static Credentials testCredentialsDecode(String json){
Credentials cred = new Credentials().decode(json);
System.out.println("encoded credentials = "+cred.encode());
return cred;
}
public static void main(String[] args) {
JSONObject jo = testJSONObjectBuild();
testJSONObjectParse(jo.toString());
JSONArray ja = testJSONArrayBuild();
testJSONArrayParse(ja.toString());
String credsJSON = testCredentialsEncode();
testCredentialsDecode(credsJSON);
}
}
To get the source code in a place, instead of having to copy the one here, see:
the code on Github

Printing all variables value from a class

I have a class with information about a Person that looks something like this:
public class Contact {
private String name;
private String location;
private String address;
private String email;
private String phone;
private String fax;
public String toString() {
// Something here
}
// Getters and setters.
}
I want toString() to return this.name +" - "+ this.locations + ... for all variables. I was trying to implement it using reflection as shown from this question but I can't manage to print instance variables.
What is the correct way to solve this?
From Implementing toString:
public String toString() {
StringBuilder result = new StringBuilder();
String newLine = System.getProperty("line.separator");
result.append( this.getClass().getName() );
result.append( " Object {" );
result.append(newLine);
//determine fields declared in this class only (no fields of superclass)
Field[] fields = this.getClass().getDeclaredFields();
//print field names paired with their values
for ( Field field : fields ) {
result.append(" ");
try {
result.append( field.getName() );
result.append(": ");
//requires access to private field:
result.append( field.get(this) );
} catch ( IllegalAccessException ex ) {
System.out.println(ex);
}
result.append(newLine);
}
result.append("}");
return result.toString();
}
Why do you want to reinvent the wheel when there are opensource that are already doing the job pretty nicely.
Both apache common-langs and spring support some very flexible builder pattern
For apache, here is how you do it reflectively
#Override
public String toString()
{
return ToStringBuilder.reflectionToString(this);
}
Here is how you do it if you only want to print fields that you care about.
#Override
public String toString()
{
return new ToStringBuilder(this)
.append("name", name)
.append("location", location)
.append("address", address)
.toString();
}
You can go as far as "styling" your print output with non-default ToStringStyle or even customizing it with your own style.
I didn't personally try spring ToStringCreator api, but it looks very similar.
If you are using Eclipse, this should be easy:
1.Press Alt+Shift+S
2.Choose "Generate toString()..."
Enjoy! You can have any template of toString()s.
This also works with getter/setters.
Generic toString() one-liner, using reflection and style customization:
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
...
public String toString()
{
return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
When accessing the field value, pass the instance rather than null.
Why not use code generation here? Eclipse, for example, will generate a reasoble toString implementation for you.
Another simple approach is to let Lombok generate the toString method for you.
For this:
Simply add Lombok to your project
Add the annotation #ToString to the definition of your class
Compile your class/project, and it is done
So for example in your case, your class would look like this:
#ToString
public class Contact {
private String name;
private String location;
private String address;
private String email;
private String phone;
private String fax;
// Getters and setters.
}
Example of output in this case:
Contact(name=John, location=USA, address=SF, email=foo#bar.com, phone=99999, fax=88888)
More details about how to use the annotation #ToString.
NB: You can also let Lombok generate the getters and setters for you, here is the full feature list.
If the output from ReflectionToStringBuilder.toString() is not enough readable for you, here is code that:
1) sorts field names alphabetically
2) flags non-null fields with asterisks in the beginning of the line
public static Collection<Field> getAllFields(Class<?> type) {
TreeSet<Field> fields = new TreeSet<Field>(
new Comparator<Field>() {
#Override
public int compare(Field o1, Field o2) {
int res = o1.getName().compareTo(o2.getName());
if (0 != res) {
return res;
}
res = o1.getDeclaringClass().getSimpleName().compareTo(o2.getDeclaringClass().getSimpleName());
if (0 != res) {
return res;
}
res = o1.getDeclaringClass().getName().compareTo(o2.getDeclaringClass().getName());
return res;
}
});
for (Class<?> c = type; c != null; c = c.getSuperclass()) {
fields.addAll(Arrays.asList(c.getDeclaredFields()));
}
return fields;
}
public static void printAllFields(Object obj) {
for (Field field : getAllFields(obj.getClass())) {
field.setAccessible(true);
String name = field.getName();
Object value = null;
try {
value = field.get(obj);
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
System.out.printf("%s %s.%s = %s;\n", value==null?" ":"*", field.getDeclaringClass().getSimpleName(), name, value);
}
}
test harness:
public static void main(String[] args) {
A a = new A();
a.x = 1;
B b = new B();
b.x=10;
b.y=20;
System.out.println("=======");
printAllFields(a);
System.out.println("=======");
printAllFields(b);
System.out.println("=======");
}
class A {
int x;
String z = "z";
Integer b;
}
class B extends A {
int y;
private double z = 12345.6;
public int a = 55;
}
Addition with #cletus answer, You have to fetch all model fields(upper hierarchy) and set field.setAccessible(true) to access private members. Here is the full snippet:
#Override
public String toString() {
StringBuilder result = new StringBuilder();
String newLine = System.getProperty("line.separator");
result.append(getClass().getSimpleName());
result.append( " {" );
result.append(newLine);
List<Field> fields = getAllModelFields(getClass());
for (Field field : fields) {
result.append(" ");
try {
result.append(field.getName());
result.append(": ");
field.setAccessible(true);
result.append(field.get(this));
} catch ( IllegalAccessException ex ) {
// System.err.println(ex);
}
result.append(newLine);
}
result.append("}");
result.append(newLine);
return result.toString();
}
private List<Field> getAllModelFields(Class aClass) {
List<Field> fields = new ArrayList<>();
do {
Collections.addAll(fields, aClass.getDeclaredFields());
aClass = aClass.getSuperclass();
} while (aClass != null);
return fields;
}
i will get my answer as follow:
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class findclass {
public static void main(String[] args) throws Exception, IllegalAccessException {
new findclass().findclass(new Object(), "objectName");
new findclass().findclass(1213, "int");
new findclass().findclass("ssdfs", "String");
}
public Map<String, String>map=new HashMap<String, String>();
public void findclass(Object c,String name) throws IllegalArgumentException, IllegalAccessException {
if(map.containsKey(c.getClass().getName() + "#" + Integer.toHexString(c.hashCode()))){
System.out.println(c.getClass().getSimpleName()+" "+name+" = "+map.get(c.getClass().getName() + "#" + Integer.toHexString(c.hashCode()))+" = "+c);
return;}
map.put(c.getClass().getName() + "#" + Integer.toHexString(c.hashCode()), name);
Class te=c.getClass();
if(te.equals(Integer.class)||te.equals(Double.class)||te.equals(Float.class)||te.equals(Boolean.class)||te.equals(Byte.class)||te.equals(Long.class)||te.equals(String.class)||te.equals(Character.class)){
System.out.println(c.getClass().getSimpleName()+" "+name+" = "+c);
return;
}
if(te.isArray()){
if(te==int[].class||te==char[].class||te==double[].class||te==float[].class||te==byte[].class||te==long[].class||te==boolean[].class){
boolean dotflag=true;
for (int i = 0; i < Array.getLength(c); i++) {
System.out.println(Array.get(c, i).getClass().getSimpleName()+" "+name+"["+i+"] = "+Array.get(c, i));
}
return;
}
Object[]arr=(Object[])c;
for (Object object : arr) {
if(object==null)
System.out.println(c.getClass().getSimpleName()+" "+name+" = null");
else {
findclass(object, name+"."+object.getClass().getSimpleName());
}
}
}
Field[] fields=c.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
if(field.get(c)==null){
System.out.println(field.getType().getSimpleName()+" "+name+"."+field.getName()+" = null");
continue;
}
findclass(field.get(c),name+"."+field.getName());
}
if(te.getSuperclass()==Number.class||te.getSuperclass()==Object.class||te.getSuperclass()==null)
return;
Field[]faFields=c.getClass().getSuperclass().getDeclaredFields();
for (Field field : faFields) {
field.setAccessible(true);
if(field.get(c)==null){
System.out.println(field.getType().getSimpleName()+" "+name+"<"+c.getClass().getSuperclass().getSimpleName()+"."+field.getName()+" = null");
continue;
}
Object check=field.get(c);
findclass(field.get(c),name+"<"+c.getClass().getSuperclass().getSimpleName()+"."+field.getName());
}
}
public void findclass(Object c,String name,Writer writer) throws IllegalArgumentException, IllegalAccessException, IOException {
if(map.containsKey(c.getClass().getName() + "#" + Integer.toHexString(c.hashCode()))){
writer.append(c.getClass().getSimpleName()+" "+name+" = "+map.get(c.getClass().getName() + "#" + Integer.toHexString(c.hashCode()))+" = "+c+"\n");
return;}
map.put(c.getClass().getName() + "#" + Integer.toHexString(c.hashCode()), name);
Class te=c.getClass();
if(te.equals(Integer.class)||te.equals(Double.class)||te.equals(Float.class)||te.equals(Boolean.class)||te.equals(Byte.class)||te.equals(Long.class)||te.equals(String.class)||te.equals(Character.class)){
writer.append(c.getClass().getSimpleName()+" "+name+" = "+c+"\n");
return;
}
if(te.isArray()){
if(te==int[].class||te==char[].class||te==double[].class||te==float[].class||te==byte[].class||te==long[].class||te==boolean[].class){
boolean dotflag=true;
for (int i = 0; i < Array.getLength(c); i++) {
writer.append(Array.get(c, i).getClass().getSimpleName()+" "+name+"["+i+"] = "+Array.get(c, i)+"\n");
}
return;
}
Object[]arr=(Object[])c;
for (Object object : arr) {
if(object==null){
writer.append(c.getClass().getSimpleName()+" "+name+" = null"+"\n");
}else {
findclass(object, name+"."+object.getClass().getSimpleName(),writer);
}
}
}
Field[] fields=c.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
if(field.get(c)==null){
writer.append(field.getType().getSimpleName()+" "+name+"."+field.getName()+" = null"+"\n");
continue;
}
findclass(field.get(c),name+"."+field.getName(),writer);
}
if(te.getSuperclass()==Number.class||te.getSuperclass()==Object.class||te.getSuperclass()==null)
return;
Field[]faFields=c.getClass().getSuperclass().getDeclaredFields();
for (Field field : faFields) {
field.setAccessible(true);
if(field.get(c)==null){
writer.append(field.getType().getSimpleName()+" "+name+"<"+c.getClass().getSuperclass().getSimpleName()+"."+field.getName()+" = null"+"\n");
continue;
}
Object check=field.get(c);
findclass(field.get(c),name+"<"+c.getClass().getSuperclass().getSimpleName()+"."+field.getName(),writer);
}
}
}

Categories