I have an entity class (account), with a column called permission, to manage the access on my website. It's mapped as string in my db, like the follow:
#Column(length = 300)
private String permissions;
In truth, this field contains a json string, for example like:
{"permissionOne" : true, "permissionTwo" : false}
The field is not mapped as JSON, because my db is MySql with an older version, which doesn't support JSON type, and I cannot change the version.
I have also a JsonHelper class:
public class JsonHelper {
/** Singleton parser instance */
private static ObjectMapper parser = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.enable(Feature.ALLOW_UNQUOTED_FIELD_NAMES, Feature.ALLOW_UNQUOTED_CONTROL_CHARS);
/** Logger instance */
private static Logger LOG = LoggerFactory.getLogger(JsonHelper.class);
/**
* converts one java object into json {#link String}g
*
* #param toConvert
* #return converted {#link String} object
*/
public static String toJsonString(Object toConvert) {
String result = null;
try {
result = parser.writeValueAsString(toConvert);
}
catch (JsonProcessingException e) {
LOG.error("Cannot parse value : " + toConvert + " StackTrace : ", e);
}
return result;
}
/**
* Converts one json {#link String} into java object
*
* #param toConvert json string to convert
* #param convertType class type to be converted into
* #return converted java object
*/
public static <T> T fromJsonString(String toConvert, Class<T> convertType) {
if (toConvert == null) return null;
T result = null;
try {
result = parser.readValue(toConvert, convertType);
}
catch (IOException e) {
LOG.error("Cannot parse value : " + convertType + " " + toConvert + " StackTrace : ", e);
}
return result;
}
/**
* Converts one java object to {#link JsonNode}
*
* #param toConvert object to convert
* #return converted json object
*/
public static JsonNode toJsonNode(Object toConvert) {
return parser.valueToTree(toConvert);
}
/**
* Converts one {#link JsonNode} into java object
*
* #param toConvert to be converted
* #param convertType type of class to convert to
* #return converted java object
*/
public static <T> T fromJsonNode(JsonNode toConvert, Class<T> convertType) {
T result = null;
try {
result = parser.treeToValue(toConvert, convertType);
}
catch (JsonProcessingException e) {
LOG.error("Cannot parse value : " + convertType + " " + toConvert +
" StackTrace : ", e);
}
return result;
}
/**
* Converts one json into list of objects
*
* #param toConvert json to convert
* #param convertType list type
* #return converted liist with objects
*/
public static <T> List<T> fromJsonNodeList(JsonNode toConvert, Class<T>
convertType) {
List<T> result = new ArrayList<>();
if (!toConvert.isArray()) return result;
for (JsonNode node : toConvert) {
result.add(fromJsonNode(node, convertType));
}
return result;
}
public static ObjectMapper getParser() {
return parser;
}
}
When I do:
Permission permission = JsonHelper.fromJsonString(account.getPermissions(), Permission.class);
permission variable is null.
I don't know why. It seems all good.
Am I missing something?
Can I do it in a different way?
thanks!
Judging from what I see in this piece of code:
public static <T> T fromJsonString(String toConvert, Class<T> convertType) {
if (toConvert == null) return null;
T result = null;
try {
result = parser.readValue(toConvert, convertType);
}
catch (IOException e) {
LOG.error("Cannot parse value : " + convertType + " " + toConvert + " StackTrace : ", e);
}
return result;
}
this method can only return null in case toConvert is null or the parser cannot read the value.
In case toConvert is null is an acceptable option (assuming the permissions field is really optional). You should perhaps log a warning that the toConvert parameter is null. Apart from that you could use Java 8's Optional as a return value here.
In the other case there is probably some garbage (non readable JSON) in your database and this will require some cleanup action apart from logging. You should try to avoid to have data in your storage which will persistently cause errors.
Related
I used soapUi to generate a Java Pojo from a WSDL, one of the generated class looks like the following below FACValidatyRequest class
package com.innovectives.octopus.gt.bank.agency.common.dto;
import javax.xml.stream.XMLStreamException;
import org.apache.axis2.databinding.ADBException;
/**
* FacValidityRequest bean class
*/
#SuppressWarnings({"unchecked",
"unused"
})
public class FacValidityRequest implements org.apache.axis2.databinding.ADBBean {
/* This type was generated from the piece of schema that had
name = FacValidityRequest
Namespace URI = http://tempuri.org/
Namespace Prefix = ns1
*/
/**
* field for FACCode
*/
protected java.lang.String localFACCode;
/* This tracker boolean wil be used to detect whether the user called the set method
* for this attribute. It will be used to determine whether to include this field
* in the serialized XML
*/
protected boolean localFACCodeTracker = false;
/**
* field for MobileNumber
*/
protected java.lang.String localMobileNumber;
/* This tracker boolean wil be used to detect whether the user called the set method
* for this attribute. It will be used to determine whether to include this field
* in the serialized XML
*/
protected boolean localMobileNumberTracker = false;
/**
* field for UniqueId
*/
protected java.lang.String localUniqueId;
/* This tracker boolean wil be used to detect whether the user called the set method
* for this attribute. It will be used to determine whether to include this field
* in the serialized XML
*/
protected boolean localUniqueIdTracker = false;
/**
* field for Hash
*/
protected java.lang.String localHash;
/* This tracker boolean wil be used to detect whether the user called the set method
* for this attribute. It will be used to determine whether to include this field
* in the serialized XML
*/
protected boolean localHashTracker = false;
public boolean isFACCodeSpecified() {
return localFACCodeTracker;
}
/**
* Auto generated getter method
* #return java.lang.String
*/
public java.lang.String getFACCode() {
return localFACCode;
}
/**
* Auto generated setter method
* #param param FACCode
*/
public void setFACCode(java.lang.String param) {
localFACCodeTracker = param != null;
this.localFACCode = param;
}
public boolean isMobileNumberSpecified() {
return localMobileNumberTracker;
}
/**
* Auto generated getter method
* #return java.lang.String
*/
public java.lang.String getMobileNumber() {
return localMobileNumber;
}
/**
* Auto generated setter method
* #param param MobileNumber
*/
public void setMobileNumber(java.lang.String param) {
localMobileNumberTracker = param != null;
this.localMobileNumber = param;
}
public boolean isUniqueIdSpecified() {
return localUniqueIdTracker;
}
/**
* Auto generated getter method
* #return java.lang.String
*/
public java.lang.String getUniqueId() {
return localUniqueId;
}
/**
* Auto generated setter method
* #param param UniqueId
*/
public void setUniqueId(java.lang.String param) {
localUniqueIdTracker = param != null;
this.localUniqueId = param;
}
public boolean isHashSpecified() {
return localHashTracker;
}
/**
* Auto generated getter method
* #return java.lang.String
*/
public java.lang.String getHash() {
return localHash;
}
/**
* Auto generated setter method
* #param param Hash
*/
public void setHash(java.lang.String param) {
localHashTracker = param != null;
this.localHash = param;
}
/**
*
* #param parentQName
* #param factory
* #return org.apache.axiom.om.OMElement
* #throws org.apache.axis2.databinding.ADBException
*/
#Override
public org.apache.axiom.om.OMElement getOMElement(
final javax.xml.namespace.QName parentQName,
final org.apache.axiom.om.OMFactory factory)
throws org.apache.axis2.databinding.ADBException {
return factory.createOMElement(new org.apache.axis2.databinding.ADBDataSource(
this, parentQName));
}
/**
*
* #param parentQName
* #param xmlWriter
* #throws XMLStreamException
* #throws ADBException
*/
#Override
public void serialize(final javax.xml.namespace.QName parentQName,
javax.xml.stream.XMLStreamWriter xmlWriter)
throws javax.xml.stream.XMLStreamException,
org.apache.axis2.databinding.ADBException {
serialize(parentQName, xmlWriter, false);
}
/**
*
* #param parentQName
* #param xmlWriter
* #param serializeType
* #throws XMLStreamException
* #throws ADBException
*/
#Override
public void serialize(final javax.xml.namespace.QName parentQName,
javax.xml.stream.XMLStreamWriter xmlWriter, boolean serializeType)
throws javax.xml.stream.XMLStreamException,
org.apache.axis2.databinding.ADBException {
java.lang.String prefix = null;
java.lang.String namespace = null;
prefix = parentQName.getPrefix();
namespace = parentQName.getNamespaceURI();
writeStartElement(prefix, namespace, parentQName.getLocalPart(),
xmlWriter);
if (serializeType) {
java.lang.String namespacePrefix = registerPrefix(xmlWriter,
"http://tempuri.org/");
if ((namespacePrefix != null) &&
(namespacePrefix.trim().length() > 0)) {
writeAttribute("xsi",
"http://www.w3.org/2001/XMLSchema-instance", "type",
namespacePrefix + ":FacValidityRequest", xmlWriter);
} else {
writeAttribute("xsi",
"http://www.w3.org/2001/XMLSchema-instance", "type",
"FacValidityRequest", xmlWriter);
}
}
if (localFACCodeTracker) {
namespace = "http://tempuri.org/";
writeStartElement(null, namespace, "FACCode", xmlWriter);
if (localFACCode == null) {
// write the nil attribute
throw new org.apache.axis2.databinding.ADBException(
"FACCode cannot be null!!");
} else {
xmlWriter.writeCharacters(localFACCode);
}
xmlWriter.writeEndElement();
}
if (localMobileNumberTracker) {
namespace = "http://tempuri.org/";
writeStartElement(null, namespace, "MobileNumber", xmlWriter);
if (localMobileNumber == null) {
// write the nil attribute
throw new org.apache.axis2.databinding.ADBException(
"MobileNumber cannot be null!!");
} else {
xmlWriter.writeCharacters(localMobileNumber);
}
xmlWriter.writeEndElement();
}
if (localUniqueIdTracker) {
namespace = "http://tempuri.org/";
writeStartElement(null, namespace, "UniqueId", xmlWriter);
if (localUniqueId == null) {
// write the nil attribute
throw new org.apache.axis2.databinding.ADBException(
"UniqueId cannot be null!!");
} else {
xmlWriter.writeCharacters(localUniqueId);
}
xmlWriter.writeEndElement();
}
if (localHashTracker) {
namespace = "http://tempuri.org/";
writeStartElement(null, namespace, "Hash", xmlWriter);
if (localHash == null) {
// write the nil attribute
throw new org.apache.axis2.databinding.ADBException(
"Hash cannot be null!!");
} else {
xmlWriter.writeCharacters(localHash);
}
xmlWriter.writeEndElement();
}
xmlWriter.writeEndElement();
}
private static java.lang.String generatePrefix(java.lang.String namespace) {
if (namespace.equals("http://tempuri.org/")) {
return "ns1";
}
return org.apache.axis2.databinding.utils.BeanUtil.getUniquePrefix();
}
/**
* Utility method to write an element start tag.
*/
private void writeStartElement(java.lang.String prefix,
java.lang.String namespace, java.lang.String localPart,
javax.xml.stream.XMLStreamWriter xmlWriter)
throws javax.xml.stream.XMLStreamException {
java.lang.String writerPrefix = xmlWriter.getPrefix(namespace);
if (writerPrefix != null) {
xmlWriter.writeStartElement(writerPrefix, localPart, namespace);
} else {
if (namespace.length() == 0) {
prefix = "";
} else if (prefix == null) {
prefix = generatePrefix(namespace);
}
xmlWriter.writeStartElement(prefix, localPart, namespace);
xmlWriter.writeNamespace(prefix, namespace);
xmlWriter.setPrefix(prefix, namespace);
}
}
/**
* Util method to write an attribute with the ns prefix
*/
private void writeAttribute(java.lang.String prefix,
java.lang.String namespace, java.lang.String attName,
java.lang.String attValue, javax.xml.stream.XMLStreamWriter xmlWriter)
throws javax.xml.stream.XMLStreamException {
java.lang.String writerPrefix = xmlWriter.getPrefix(namespace);
if (writerPrefix != null) {
xmlWriter.writeAttribute(writerPrefix, namespace, attName, attValue);
} else {
xmlWriter.writeNamespace(prefix, namespace);
xmlWriter.setPrefix(prefix, namespace);
xmlWriter.writeAttribute(prefix, namespace, attName, attValue);
}
}
/**
* Util method to write an attribute without the ns prefix
*/
private void writeAttribute(java.lang.String namespace,
java.lang.String attName, java.lang.String attValue,
javax.xml.stream.XMLStreamWriter xmlWriter)
throws javax.xml.stream.XMLStreamException {
if (namespace.equals("")) {
xmlWriter.writeAttribute(attName, attValue);
} else {
xmlWriter.writeAttribute(registerPrefix(xmlWriter, namespace),
namespace, attName, attValue);
}
}
/**
* Util method to write an attribute without the ns prefix
*/
private void writeQNameAttribute(java.lang.String namespace,
java.lang.String attName, javax.xml.namespace.QName qname,
javax.xml.stream.XMLStreamWriter xmlWriter)
throws javax.xml.stream.XMLStreamException {
java.lang.String attributeNamespace = qname.getNamespaceURI();
java.lang.String attributePrefix = xmlWriter.getPrefix(attributeNamespace);
if (attributePrefix == null) {
attributePrefix = registerPrefix(xmlWriter, attributeNamespace);
}
java.lang.String attributeValue;
if (attributePrefix.trim().length() > 0) {
attributeValue = attributePrefix + ":" + qname.getLocalPart();
} else {
attributeValue = qname.getLocalPart();
}
if (namespace.equals("")) {
xmlWriter.writeAttribute(attName, attributeValue);
} else {
registerPrefix(xmlWriter, namespace);
xmlWriter.writeAttribute(attributePrefix, namespace, attName,
attributeValue);
}
}
/**
* method to handle Qnames
*/
private void writeQName(javax.xml.namespace.QName qname,
javax.xml.stream.XMLStreamWriter xmlWriter)
throws javax.xml.stream.XMLStreamException {
java.lang.String namespaceURI = qname.getNamespaceURI();
if (namespaceURI != null) {
java.lang.String prefix = xmlWriter.getPrefix(namespaceURI);
if (prefix == null) {
prefix = generatePrefix(namespaceURI);
xmlWriter.writeNamespace(prefix, namespaceURI);
xmlWriter.setPrefix(prefix, namespaceURI);
}
if (prefix.trim().length() > 0) {
xmlWriter.writeCharacters(prefix + ":" +
org.apache.axis2.databinding.utils.ConverterUtil.convertToString(
qname));
} else {
// i.e this is the default namespace
xmlWriter.writeCharacters(org.apache.axis2.databinding.utils.ConverterUtil.convertToString(
qname));
}
} else {
xmlWriter.writeCharacters(org.apache.axis2.databinding.utils.ConverterUtil.convertToString(
qname));
}
}
private void writeQNames(javax.xml.namespace.QName[] qnames,
javax.xml.stream.XMLStreamWriter xmlWriter)
throws javax.xml.stream.XMLStreamException {
if (qnames != null) {
// we have to store this data until last moment since it is not possible to write any
// namespace data after writing the charactor data
StringBuilder stringToWrite = new StringBuilder();
java.lang.String namespaceURI = null;
java.lang.String prefix = null;
for (int i = 0; i < qnames.length; i++) {
if (i > 0) {
stringToWrite.append(" ");
}
namespaceURI = qnames[i].getNamespaceURI();
if (namespaceURI != null) {
prefix = xmlWriter.getPrefix(namespaceURI);
if ((prefix == null) || (prefix.length() == 0)) {
prefix = generatePrefix(namespaceURI);
xmlWriter.writeNamespace(prefix, namespaceURI);
xmlWriter.setPrefix(prefix, namespaceURI);
}
if (prefix.trim().length() > 0) {
stringToWrite.append(prefix).append(":")
.append(org.apache.axis2.databinding.utils.ConverterUtil.convertToString(
qnames[i]));
} else {
stringToWrite.append(org.apache.axis2.databinding.utils.ConverterUtil.convertToString(
qnames[i]));
}
} else {
stringToWrite.append(org.apache.axis2.databinding.utils.ConverterUtil.convertToString(
qnames[i]));
}
}
xmlWriter.writeCharacters(stringToWrite.toString());
}
}
/**
* Register a namespace prefix
*/
private java.lang.String registerPrefix(
javax.xml.stream.XMLStreamWriter xmlWriter, java.lang.String namespace)
throws javax.xml.stream.XMLStreamException {
java.lang.String prefix = xmlWriter.getPrefix(namespace);
if (prefix == null) {
prefix = generatePrefix(namespace);
javax.xml.namespace.NamespaceContext nsContext = xmlWriter.getNamespaceContext();
while (true) {
java.lang.String uri = nsContext.getNamespaceURI(prefix);
if ((uri == null) || (uri.length() == 0)) {
break;
}
prefix = org.apache.axis2.databinding.utils.BeanUtil.getUniquePrefix();
}
xmlWriter.writeNamespace(prefix, namespace);
xmlWriter.setPrefix(prefix, namespace);
}
return prefix;
}
/**
* Factory class that keeps the parse method
*/
public static class Factory {
private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(Factory.class);
/**
* static method to create the object
* Precondition: If this object is an element, the current or next start element starts this object and any intervening reader events are ignorable
* If this object is not an element, it is a complex type and the reader is at the event just after the outer start element
* Postcondition: If this object is an element, the reader is positioned at its end element
* If this object is a complex type, the reader is positioned at the end element of its outer element
* #param reader
* #return
* #throws java.lang.Exception
*/
public static FacValidityRequest parse(
javax.xml.stream.XMLStreamReader reader) throws java.lang.Exception {
FacValidityRequest object = new FacValidityRequest();
int event;
javax.xml.namespace.QName currentQName = null;
java.lang.String nillableValue = null;
java.lang.String prefix = "";
java.lang.String namespaceuri = "";
try {
while (!reader.isStartElement() && !reader.isEndElement())
reader.next();
currentQName = reader.getName();
if (reader.getAttributeValue(
"http://www.w3.org/2001/XMLSchema-instance", "type") != null) {
java.lang.String fullTypeName = reader.getAttributeValue("http://www.w3.org/2001/XMLSchema-instance",
"type");
if (fullTypeName != null) {
java.lang.String nsPrefix = null;
if (fullTypeName.indexOf(":") > -1) {
nsPrefix = fullTypeName.substring(0,
fullTypeName.indexOf(":"));
}
nsPrefix = (nsPrefix == null) ? "" : nsPrefix;
java.lang.String type = fullTypeName.substring(fullTypeName.indexOf(
":") + 1);
if (!"FacValidityRequest".equals(type)) {
//find namespace for the prefix
java.lang.String nsUri = reader.getNamespaceContext()
.getNamespaceURI(nsPrefix);
return (FacValidityRequest) ExtensionMapper.getTypeObject(nsUri,
type, reader);
}
}
}
// Note all attributes that were handled. Used to differ normal attributes
// from anyAttributes.
java.util.Vector handledAttributes = new java.util.Vector();
reader.next();
while (!reader.isStartElement() && !reader.isEndElement())
reader.next();
if (reader.isStartElement() &&
new javax.xml.namespace.QName("http://tempuri.org/",
"FACCode").equals(reader.getName())) {
nillableValue = reader.getAttributeValue("http://www.w3.org/2001/XMLSchema-instance",
"nil");
if ("true".equals(nillableValue) ||
"1".equals(nillableValue)) {
throw new org.apache.axis2.databinding.ADBException(
"The element: " + "FACCode" + " cannot be null");
}
java.lang.String content = reader.getElementText();
object.setFACCode(org.apache.axis2.databinding.utils.ConverterUtil.convertToString(
content));
reader.next();
} // End of if for expected property start element
else {
}
while (!reader.isStartElement() && !reader.isEndElement())
reader.next();
if (reader.isStartElement() &&
new javax.xml.namespace.QName("http://tempuri.org/",
"MobileNumber").equals(reader.getName())) {
nillableValue = reader.getAttributeValue("http://www.w3.org/2001/XMLSchema-instance",
"nil");
if ("true".equals(nillableValue) ||
"1".equals(nillableValue)) {
throw new org.apache.axis2.databinding.ADBException(
"The element: " + "MobileNumber" +
" cannot be null");
}
java.lang.String content = reader.getElementText();
object.setMobileNumber(org.apache.axis2.databinding.utils.ConverterUtil.convertToString(
content));
reader.next();
} // End of if for expected property start element
else {
}
while (!reader.isStartElement() && !reader.isEndElement())
reader.next();
if (reader.isStartElement() &&
new javax.xml.namespace.QName("http://tempuri.org/",
"UniqueId").equals(reader.getName())) {
nillableValue = reader.getAttributeValue("http://www.w3.org/2001/XMLSchema-instance",
"nil");
if ("true".equals(nillableValue) ||
"1".equals(nillableValue)) {
throw new org.apache.axis2.databinding.ADBException(
"The element: " + "UniqueId" + " cannot be null");
}
java.lang.String content = reader.getElementText();
object.setUniqueId(org.apache.axis2.databinding.utils.ConverterUtil.convertToString(
content));
reader.next();
} // End of if for expected property start element
else {
}
while (!reader.isStartElement() && !reader.isEndElement())
reader.next();
if (reader.isStartElement() &&
new javax.xml.namespace.QName("http://tempuri.org/",
"Hash").equals(reader.getName())) {
nillableValue = reader.getAttributeValue("http://www.w3.org/2001/XMLSchema-instance",
"nil");
if ("true".equals(nillableValue) ||
"1".equals(nillableValue)) {
throw new org.apache.axis2.databinding.ADBException(
"The element: " + "Hash" + " cannot be null");
}
java.lang.String content = reader.getElementText();
object.setHash(org.apache.axis2.databinding.utils.ConverterUtil.convertToString(
content));
reader.next();
} // End of if for expected property start element
else {
}
while (!reader.isStartElement() && !reader.isEndElement())
reader.next();
if (reader.isStartElement()) {
// 2 - A start element we are not expecting indicates a trailing invalid property
throw new org.apache.axis2.databinding.ADBException(
"Unexpected subelement " + reader.getName());
}
} catch (javax.xml.stream.XMLStreamException e) {
throw new java.lang.Exception(e);
}
return object;
}
} //end of factory class
}
I tried to use the POJO and set its values as I have done below but I can not view the String representation of my POJO when I print it out to console using system.out.println I can not also convert my POJO to string to be sent across the internet, rather it gives me the following below which I guess is an address in memory but I want the string representation
com.innovectives.octopus.gt.bank.agency.common.dto.FacValidityRequest#2d9b42e2
FacValidityRequest commonGTRequest = new FacValidityRequest();
commonGTRequest.setFACCode("1095780292");
commonGTRequest.setMobileNumber("08036952110");
commonGTRequest.setUniqueId(OctopusHelper.randomUUIDString());
commonGTRequest.setHash("hashing");
JAXBContext context = JAXBContext.newInstance(FacValidityRequest.class);
System.out.println("data = "+ ConvertXmlToString(commonGTRequest, context));
exchange.getIn(FacValidityRequest.class);
exchange.getIn().setBody(commonGTRequest);
LOG.info("end convertFacValidationRequest...\n" + exchange.getIn().getBody(String.class));
SAMPLE REQUEST
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:tem="http://tempuri.org/">
<soap:Header/>
<soap:Body>
<tem:FACValidityRequest>
<!--Optional:-->
<tem:facreq>
<!--Optional:-->
<tem:FACCode>?</tem:FACCode>
<!--Optional:-->
<tem:MobileNumber>?</tem:MobileNumber>
<!--Optional:-->
<tem:UniqueId>?</tem:UniqueId>
<!--Optional:-->
<tem:Hash>?</tem:Hash>
</tem:facreq>
</tem:FACValidityRequest>
</soap:Body>
</soap:Envelope>
How do I achieve this, with the generated POJO above.
What you get is an output of default Java Object.toString() implementation and it is correct - your class does not override toString().
So, either check Axis2/SoapUI documentation about is there a way to generate toString() method or (if not)
depends on how do you want to see your object String representation you can:
override toString() after class generated
create some utility to convert your object to String
simplest way is to use Apache BeanUtils.describe(Object obj) method
but if you want see actual XML as string you need to use one of serialize methods generated for you by Axis2.
something like:
// use ByteArrayOutputStream as example
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
XMLStreamWriter xmlWriter = XMLStreamWriterFactory.create(outStream);
// fake line !!! check Axis2 documentation what you need to pass as Parent QName to Serialize an object
javax.xml.namespace.QName parentQName = new javax.xml.namespace.QName("http://tempuri.org/","FacValidityRequest", "ns1");
// This is a main point to get a XML String out of POJO
myFacValidityRequestObject.serialize(parentQName , xmlWriter);
System.out.println(new String(outStream.toByteArray()));
xmlWriter.close();
You need just find out what actual Parent QName parameter must be there (in my example it is just a fake one)
I have a Request Class that contains another class object. Now I want to parse a nested JSON as Request Class Object.
I am trying using ObjectMapper but its throwing exceptions. Please help me to do that using java Jackson.
{
"filters":[
{
"key":"CustomerId",
"op":"=",
"value" : "1"
},
{
"key":"userName",
"op":"=",
"value" : "admin"
}
],
"startIndex" : 1,
"size" : 10,
"OrderBy" :
{
"propertyId" : "userName",
"Desc" : false
},
"TimeRange" : {
"startTimestamp" : 1,
"endTimestamp" :10
}
}
Logic:
public static class OrderBy {
private String propertyId;
private boolean desc = true;
}
class TimeRange {
private Long startTimestamp;
private Long endTimestamp;
}
class Filter {
private String propertyId;
private String op;
private Object value;
}
public class Request {
private List<Filter> filters;
private TimeRange timeRange;
private OrderBy orderBy;
private int startIndex = 0;
private int size = 20;
}
I give you a Jaskson Util Tools class.
package com.jackson.utils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* The class JacksonUtil
*
* json字符与对像转换
*
* #version: $Revision$ $Date$ $LastChangedBy$
*
*/
public final class JacksonUtil {
public static ObjectMapper objectMapper;
/**
* 使用泛型方法,把json字符串转换为相应的JavaBean对象。
* (1)转换为普通JavaBean:readValue(json,Student.class)
* (2)转换为List,如List<Student>,将第二个参数传递为Student
* [].class.然后使用Arrays.asList();方法把得到的数组转换为特定类型的List
*
* #param jsonStr
* #param valueType
* #return
*/
public static <T> T readValue(String jsonStr, Class<T> valueType) {
if (objectMapper == null) {
objectMapper = new ObjectMapper();
}
try {
return objectMapper.readValue(jsonStr, valueType);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* json数组转List
* #param jsonStr
* #param valueTypeRef
* #return
*/
public static <T> T readValue(String jsonStr, TypeReference<T> valueTypeRef){
if (objectMapper == null) {
objectMapper = new ObjectMapper();
}
try {
return objectMapper.readValue(jsonStr, valueTypeRef);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 把JavaBean转换为json字符串
*
* #param object
* #return
*/
public static String toJSon(Object object) {
if (objectMapper == null) {
objectMapper = new ObjectMapper();
}
try {
return objectMapper.writeValueAsString(object);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
Now ,you can use blow code covert to Request :
String userBeanToJson = "your json string";//please replace this for your need json
Request jsonToUserBean = JacksonUtil.readValue(userBeanToJson, Request.class);
Hope it is useful for you.
I'm currently working in migrating a project to java, keeping the data intact (database). Most data are taken via stored procedures(SP), and there's a hell lot of SP in the database.
So, while executing each SP, I have to write a class for that, which is building up a huge pile of classes.
Hence, is there any way to generalize the class, so that I could transform every SP results to this class, and then to client side(as json)?
Following scenarios are hidden n ma qn:
Dynamic number of fields.
Dynamic field names.
Type could be string
(could deal with that).
I have tried sending data as java.util.List, but that doesn't comes in a pretty format. Have to take data assuming indexes.
PS: I have searched for the same, but couldn't find any. And sorry if I'm asking for too much.
Yes, it should be possible to write such a generic class. Here is a small example class as a starting point for you. I use Firebird with the example database employee.fdb because there are already some stored procedures defined.
So to connect to the Firebird server, I use the Jaybird JDBC driver and include the jaybird-full-2.2.5.jar JAR file.
There are several different JSON libraries for JAVA. I use the JSR 353: Java API for JSON Processing - Reference Implementation here in streaming mode (like StaX for XML). So the second external JAR here is javax.json-1.0.4.jar.
My example works only for stored procedures returning result sets. For stored procedures with output parameters a CallableStatement should be used instead of a PreparedStatement.
First, a generic SQL statement is created for the specific stored procedure with its input parameters. To call the stored procedure, a PreparedStatemend is used. The parameters are set according to the individual parameter types. (Procedures createSql() and createStatement())
In procedure convertToJson() the method ResultSet.getMetaData() is used to get the result set's column information (how many columns, column name and column type).
The executeStoredProcedure() methods are public API methods to call.
The main() method connects to the èmployee.fdb database and calls three stored procedures: GET_EMP_PROJ, MAIL_LABEL and ORG_CHART.
package com.genericsptojson;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;
import javax.json.Json;
import javax.json.stream.JsonGenerator;
import javax.json.stream.JsonGeneratorFactory;
public class GenericSpToJson {
private static final String DB_URL = "jdbc:firebirdsql:localhost/3050:/var/lib/firebird/2.5/data/employee.fdb";
private static final String DB_USER = "SYSDBA";
private static final String DB_PWD = "***";
private Connection con;
public GenericSpToJson(Connection con) {
this.con = con;
}
/**
* Creates the SQL to call the stored procedure.
*
* #param spName
* Name of stored procecdure to call
* #param paramCount
* number of input parameters
* #return SQL with placeholders for input parameters
*/
private String createSql(String spName, int paramCount) {
if(paramCount > 0) {
final StringBuilder params = new StringBuilder();
boolean isFirst = true;
for(int i = 0; i < paramCount; i++) {
if(isFirst) {
isFirst = false;
} else {
params.append(", ");
}
params.append('?');
}
return String.format("SELECT * FROM %s (%s)", spName, params.toString());
} else {
return String.format("SELECT * FROM %s", spName);
}
}
/**
* Creates a PreparedStatement to call the stored procedure. This works only
* for stored procedures creating result sets. Stored procedures with OUT
* parameters should be handled by a CallableStatement instead.
*
* #param spName
* The stored procedure name to be called.
* #param params
* The input parameters.
* #return A prepared statement. All parameters are set.
* #throws SQLException
*/
private PreparedStatement createStatement(String spName, Object... params) throws SQLException {
final PreparedStatement stmt = con.prepareStatement(createSql(spName, params.length));
for(int i = 0; i < params.length; i++) {
final Object param = params[i];
if(param instanceof String) {
stmt.setString(i + 1, (String) param);
} else if(param instanceof Integer) {
stmt.setInt(i + 1, ((Integer) param).intValue());
} else {
// Handle other param types ...
}
}
return stmt;
}
/**
* Converts the result set to JSON in streaming mode.
*
* #param spName
* The stored procedure name.
* #param rs
* The result set of the stored procedure call.
* #param out
* The output stream to write the JSON into.
* #throws SQLException
*/
private void convertToJson(String spName, ResultSet rs, OutputStream out) throws SQLException {
// Get the result set meta data to obtain column information on the fly.
final ResultSetMetaData metaData = rs.getMetaData();
// Create the JSON generator with pretty printing
final Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JsonGenerator.PRETTY_PRINTING, true);
final JsonGeneratorFactory jsonGeneratorFactory = Json.createGeneratorFactory(properties);
final JsonGenerator generator = jsonGeneratorFactory.createGenerator(out);
generator.writeStartObject(); // root object
generator.write("storedProcedureName", spName);
generator.write("columnCount", metaData.getColumnCount());
generator.writeStartArray("records"); // records array
while(rs.next()) {
generator.writeStartObject(); // record object
// Each record object contains one field for every column.
// The field name is the columns name.
for(int col = 1; col <= metaData.getColumnCount(); col++) {
final String fieldName = metaData.getColumnName(col);
switch(metaData.getColumnType(col)) {
case Types.INTEGER:
final int intValue = rs.getInt(col);
if(rs.wasNull()) {
generator.writeNull(fieldName);
} else {
generator.write(fieldName, intValue);
}
break;
case Types.VARCHAR:
case Types.CHAR:
String stringValue = rs.getString(col);
if(rs.wasNull()) {
generator.writeNull(fieldName);
} else {
if(metaData.getColumnType(col) == Types.CHAR) {
stringValue = stringValue.trim();
}
generator.write(fieldName, stringValue);
}
break;
// Handle other types here
default:
System.out.println(String.format("Unhandled SQL type: %s", metaData.getColumnTypeName(col)));
}
}
generator.writeEnd(); // record object
}
generator.writeEnd(); // records array
generator.writeEnd(); // root object
generator.flush();
generator.close();
}
/**
* Executes the stored procedures with the given input parameters and creates
* JSON in streaming mode.
*
* #param spName
* The name of the stored procedure.
* #param out
* The output stream to write the generated JSON into.
* #param params
* The stored procedure's parameters.
*/
public void executeStoredProcedure(String spName, OutputStream out, Object... params) {
PreparedStatement stmt = null;
ResultSet rs = null;
try {
stmt = createStatement(spName, params);
rs = stmt.executeQuery();
convertToJson(spName, rs, out);
} catch (SQLException e) {
e.printStackTrace();
} finally {
// Cleaning up ...
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
/**
* Convenience method to call the stored procedure and create a JSON string.
* This should only be called for short result sets. For longer result sets
* use {#link #executeStoredProcedure(String, OutputStream, Object...)} where
* it is not necessary to hold the entire JSON document in memory.
*
* #param spName
* The name of the stored procedure to call.
* #param params
* The stored procedure's parameters
* #return The stored procedure's call result as a JSON string.
* #throws UnsupportedEncodingException
*/
public String executeStoredProcedure(String spName, Object... params) throws UnsupportedEncodingException {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
executeStoredProcedure(spName, out, params);
return out.toString("UTF-8");
}
public static void main(String[] args) {
Connection con = null;
try {
Class.forName("org.firebirdsql.jdbc.FBDriver");
con = DriverManager.getConnection(DB_URL, DB_USER, DB_PWD);
final GenericSpToJson converter = new GenericSpToJson(con);
System.out.println("Executing stored procedure GET_EMP_PROJ (8):\n"
+ converter.executeStoredProcedure("GET_EMP_PROJ", 8));
System.out.println("\n\nExecuting stored procedure MAIL_LABEL (1015):\n"
+ converter.executeStoredProcedure("MAIL_LABEL", 1015));
System.out.println("\n\nExecuting stored procedure ORG_CHART:\n"
+ converter.executeStoredProcedure("ORG_CHART"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
The output is (shortened):
Executing stored procedure GET_EMP_PROJ (8):
{
"storedProcedureName":"GET_EMP_PROJ",
"columnCount":1,
"records":[
{
"PROJ_ID":"VBASE"
},
{
"PROJ_ID":"GUIDE"
},
{
"PROJ_ID":"MKTPR"
}
]
}
Executing stored procedure MAIL_LABEL (1015):
{
"storedProcedureName":"MAIL_LABEL",
"columnCount":6,
"records":[
{
"LINE1":"GeoTech Inc.",
"LINE2":"K.M. Neppelenbroek",
"LINE3":"P.0.Box 702",
"LINE4":"",
"LINE5":null,
"LINE6":"Netherlands 2514"
}
]
}
Executing stored procedure ORG_CHART:
{
"storedProcedureName":"ORG_CHART",
"columnCount":5,
"records":[
{
"HEAD_DEPT":null,
"DEPARTMENT":"Corporate Headquarters",
"MNGR_NAME":"Bender, Oliver H.",
"TITLE":"CEO",
"EMP_CNT":2
},
{
"HEAD_DEPT":"Corporate Headquarters",
"DEPARTMENT":"Sales and Marketing",
"MNGR_NAME":"MacDonald, Mary S.",
"TITLE":"VP",
"EMP_CNT":2
},
// ... SNIP ...
{
"HEAD_DEPT":"Corporate Headquarters",
"DEPARTMENT":"Finance",
"MNGR_NAME":"Steadman, Walter",
"TITLE":"CFO",
"EMP_CNT":2
}
]
}
I am developing an java application that accepts SOAP message. The body of the SOAP contains various documents. From time to time their number varies (depending on the version of the album).
For their analysis I am trying to apply a pattern Abstract Factory.
But my implementation, I ran into a problem:
IAlbumFactory albumFactory = AlbumFactory.buildDocument (Album.A_5_0_12);
The first parameter has I can point to any type of enum CustomDocument (although CustomDocument.DO1 only valid Du). And this error only shows up in RunTime
IDocumentEntity <Du, org.w3c.dom.Element> documentEntity =
albumFactory.getWorker (CustomDocument.DO1);
how to avoid it?
Some class:
public interface IDocumentEntity<T,E> {
T getReport(E e) throws JAXBException ;
}
public interface IAlbumFactory {
IDocumentEntity getWorker(CustomDocument document);
}
/**
* Class for convert document DO1 (album 5.0.12) from org.w3c.dom.Element to Du
* entity type
*
* #author uas
*/
public class DO1_5_0_12 implements IDocumentEntity<Du, org.w3c.dom.Element> {
protected DO1ReportInType unmarshall(org.w3c.dom.Element e) throws JAXBException {
DO1ReportInType resultType = null;
JAXBContext result = JAXBContextHelper_DO1.getJaxbContextInstance();
Unmarshaller u = result.createUnmarshaller();
Object c = u.unmarshal(e);
if (c instanceof JAXBElement) {
JAXBElement jaxbe = (JAXBElement) c;
resultType = (DO1ReportInType) JAXBIntrospector.getValue(jaxbe);
}
return resultType;
}
#Override
public Du getReport(org.w3c.dom.Element e) throws JAXBException {
DO1ReportInType dO1Report = unmarshall(e);
DO1ReportIn_JAXBtoORCL btoORCL = new DO1ReportIn_JAXBtoORCL(dO1Report);
return btoORCL.getReport();
}
}
Factory for Album 5_0_12.
public class AlbumFactory_5_0_12 implements IAlbumFactory {
/**
* Return documentWorker byn CustomDocument value
* #param customDocument
* #return throws IllegalArgumentException
*/
#Override
public IDocumentEntity getWorker(CustomDocument customDocument) {
IDocumentEntity doc = null;
switch (customDocument) {
case DO1:
doc = new DO1_5_0_12();
break;
case DO2:
doc = new DO2_5_0_12();
break;
default:
throw new IllegalArgumentException("For album 5.0.12 " + customDocument.DocName() + " not support");
}
return doc;
}
}
public class AlbumFactory {
private AlbumFactory() {
}
public static IAlbumFactory buildDocument(Album album) {
IAlbumFactory result = null;
switch (album) {
case A_5_0_12:
result = new AlbumFactory_5_0_12();
break;
default:
throw new IllegalArgumentException("This version " + album.AlbumName() + " is not support");
}
return result;
}
}
I am trying to implement a crossfield validation (JSR-303) with a custom annotation on class level. However the isValid method is not called (but the initialize method).
So my question is: Why is the isValid method not being called for this class level validator? Defining it on property level works!
I tried it on JBoss AS 7 and Websphere AS 8.
Here is the code and a JUnit test (which works)
Test.java
public class Test {
#org.junit.Test
public void test() throws ParseException {
Person person = new Person();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMDD");
person.setPartyClosingDateFrom(new Date());
person.setPartyClosingDateTo(sdf.parse("20120210"));
Set<ConstraintViolation<Person>> violations = Validation.buildDefaultValidatorFactory().getValidator().validate(person);
for(ConstraintViolation<Person> violation : violations) {
System.out.println("Message:- " + violation.getMessage());
}
}
}
DateCompare.java
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
#Target({ TYPE})
#Retention(RUNTIME)
#Constraint(validatedBy = DateCompareValidator.class)
#Documented
public #interface DateCompare {
/** First date. */
String firstDate();
/** Second date. */
String secondDate();
Class<?>[] constraints() default {};
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String message() default "totally wrong, dude!";
DateValidator.DateComparisonMode matchMode() default
DateValidator.DateComparisonMode.EQUAL;
}
DateCompareValidator.java
public class DateCompareValidator implements ConstraintValidator<DateCompare, Object> {
/** describes the mode the validator should use**/
private DateValidator.DateComparisonMode comparisonMode;
/** The first date field name. */
private String firstDateFieldName;
/** The second date field name. */
private String secondDateFieldName;
/** the message to be used **/
private String messageKey = "failure";
/**
* Initialize.
*
* This method is used to set the parameters ans is REQUIRED even if you don't use any parameters
*
* #param constraintAnnotation the constraint annotation
*/
#Override
public void initialize(final DateCompare constraintAnnotation) {
this.comparisonMode = constraintAnnotation.matchMode();
this.firstDateFieldName = constraintAnnotation.firstDate();
this.secondDateFieldName = constraintAnnotation.secondDate();
}
/**
* Checks if it is valid.
*
* #param target the target
* #param context the context
* #return true, if is valid
*/
#Override
public boolean isValid(final Object target, final ConstraintValidatorContext context) {
boolean isValid = true;
final Date valueDate1 = DateCompareValidator.getPropertyValue(Date.class, this.firstDateFieldName, target);
final Date valueDate2 = DateCompareValidator.getPropertyValue(Date.class, this.secondDateFieldName, target);
if (isValid) {
isValid = DateValidator.isValid(valueDate1, valueDate2, this.comparisonMode);
} else {
// at this point comparisonMode does not fit tp the result and we have to
// design an error Message
final ResourceBundle messageBundle = ResourceBundle.getBundle("resources.messages");
final MessageFormat message = new MessageFormat(messageBundle.getString(this.messageKey));
final Object[] messageArguments = { messageBundle.getString(this.messageKey + "." + this.comparisonMode) };
// replace the default-message with the one we just created
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(message.format(messageArguments)).addConstraintViolation();
isValid = false;
}
return isValid;
}
public static <T> T getPropertyValue(final Class<T> requiredType, final String propertyName, final Object instance) {
if (requiredType == null) {
throw new IllegalArgumentException("Invalid argument. requiredType must NOT be null!");
}
if (propertyName == null) {
throw new IllegalArgumentException("Invalid argument. PropertyName must NOT be null!");
}
if (instance == null) {
throw new IllegalArgumentException("Invalid argument. Object instance must NOT be null!");
}
T returnValue = null;
try {
final PropertyDescriptor descriptor = new PropertyDescriptor(propertyName, instance.getClass());
final Method readMethod = descriptor.getReadMethod();
if (readMethod == null) {
throw new IllegalStateException("Property '" + propertyName + "' of " + instance.getClass().getName()
+ " is NOT readable!");
}
if (requiredType.isAssignableFrom(readMethod.getReturnType())) {
try {
final Object propertyValue = readMethod.invoke(instance);
returnValue = requiredType.cast(propertyValue);
} catch (final Exception e) {
e.printStackTrace(); // unable to invoke readMethod
}
}
} catch (final IntrospectionException e) {
throw new IllegalArgumentException("Property '" + propertyName + "' is NOT defined in "
+ instance.getClass().getName() + "!", e);
}
return returnValue;
}
DateValidator.java
public class DateValidator {
/**
* The Enum DateComparisonMode.
*
* Determins which Type of validation is used
*/
public enum DateComparisonMode {
/** the given Date must be BEFORE the referenced Date */
BEFORE,
/** the given Date must be BEFORE_OR_EQUAL the referenced Date */
BEFORE_OR_EQUAL,
/** the given Date must be EQUAL the referenced Date */
EQUAL,
/** the given Date must be AFTER_OR_EQUAL the referenced Date */
AFTER_OR_EQUAL,
/** the given Date must be AFTER the referenced Date */
AFTER;
}
/**
* Compare 2 Date Values based on a given Comparison Mode.
*
* #param baseDate the base date
* #param valuationDate the valuation date
* #param comparisonMode the comparison mode
* #return true, if is valid
*/
public static boolean isValid(final Date baseDate, final Date valuationDate, final DateComparisonMode comparisonMode) {
// Timevalue of both dates will be set to 00:00:0000
final Date compValuationDate = DateValidator.convertDate(valuationDate);
final Date compBaseDate = DateValidator.convertDate(baseDate);
// compare the values
final int result = compValuationDate.compareTo(compBaseDate);
// match the result to the comparisonMode and return true
// if rule is fulfilled
switch (result) {
case -1:
if (comparisonMode == DateComparisonMode.BEFORE) {
return true;
}
if (comparisonMode == DateComparisonMode.BEFORE_OR_EQUAL) {
return true;
}
break;
case 0:
if (comparisonMode == DateComparisonMode.BEFORE_OR_EQUAL) {
return true;
}
if (comparisonMode == DateComparisonMode.EQUAL) {
return true;
}
if (comparisonMode == DateComparisonMode.AFTER_OR_EQUAL) {
return true;
}
break;
case 1:
if (comparisonMode == DateComparisonMode.AFTER) {
return true;
}
if (comparisonMode == DateComparisonMode.AFTER_OR_EQUAL) {
return true;
}
break;
default:
return false; // should not happen....
}
return false;
}
/**
* Convert date.
*
* sets the time Value of a given Date filed to 00:00:0000
*
* #param t the t
* #return the date
*/
private static Date convertDate(final Date t) {
final Calendar calendar = Calendar.getInstance();
calendar.setTime(t);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return (calendar.getTime());
}
Especially the property retrieval was taken from this post question
JSF 2.0 doesn't call class level validation constraints.
From JSF validation:
JSF 2 provides built-in integration with JSR-303 constraints. When you
are using bean validation in your application, JSF automatically uses
the constraints for beans that are referenced by UIInput values.
You have to call it manually, or you can try Seam Faces which has an extension <f:validateBean>