Java BeanUtilsBean : Convert Date to String - java

I am trying to run BeanUtilsBean.getInstance().populate(...) but on the HTML form, there is a field that carries String representation of Date of Birth. The object bean has the field type of java.util.Date
Read some search from Ggl that have to build custom converters but not quite understand how to do that.
Anyone can help?
My code:
public static void main(String[] args) {
Map<String, String[]> formData = new HashMap<String, String[]>();
formData.put("email", new String[]{"danny#gmail.com"});
formData.put("firstName", new String[]{"danny"});
formData.put("lastName", new String[]{"miller"});
formData.put("dob", new String[]{"15-Apr-1980"});
formData.put("userName", new String[]{"dannymiller"});
try {
Consumer consumer = new Consumer();
DateTimeConverter dtConverter = new DateConverter();
dtConverter.setPattern("dd/MMM/yyyy");
ConvertUtilsBean convertUtilsBean = new ConvertUtilsBean();
convertUtilsBean.deregister(Date.class);
convertUtilsBean.register(dtConverter, Date.class);
BeanUtilsBean beanUtilsBean = new BeanUtilsBean(convertUtilsBean, new PropertyUtilsBean());
beanUtilsBean.populate(consumer, formData);
if (consumer != null) {
System.out.println(consumer.getEmail());
System.out.println(consumer.getFirstName());
System.out.println(consumer.getLastName());
System.out.println(consumer.getDob());
System.out.println(consumer.getUserName());
}
} catch (Exception e) {
e.printStackTrace();
}
The return error:
Apr 22, 2011 11:14:45 PM
org.apache.commons.beanutils.converters.DateTimeConverter
toDate WARNING: DateConverter does
not support default String to 'Date'
conversion. Apr 22, 2011 11:14:45 PM
org.apache.commons.beanutils.converters.DateTimeConverter
toDate WARNING: (N.B. Re-configure
Converter or use alternative
implementation) Exception in thread
"main"
org.apache.commons.beanutils.ConversionException:
DateConverter does not support default
String to 'Date' conversion. at
org.apache.commons.beanutils.converters.DateTimeConverter.toDate(DateTimeConverter.java:468)
at
org.apache.commons.beanutils.converters.DateTimeConverter.convertToType(DateTimeConverter.java:343)
at
org.apache.commons.beanutils.converters.AbstractConverter.convert(AbstractConverter.java:156)
at
org.apache.commons.beanutils.converters.ConverterFacade.convert(ConverterFacade.java:60)
at
org.apache.commons.beanutils.ConvertUtilsBean.convert(ConvertUtilsBean.java:470)
at
org.apache.commons.beanutils.BeanUtilsBean.setProperty(BeanUtilsBean.java:1008)
at
org.apache.commons.beanutils.BeanUtilsBean.populate(BeanUtilsBean.java:830)
at
com.ymatch.test.BeanTest.main(BeanTest.java:32)

You need a SimpleDateFormat by which to parse the given string according to a specified format. For that you'd need to handle the conversion manually - name the request parameter differently and then set it manually.
But beanutils has a conversion utility, so you can use it instead (this code can be executed once per application):
DateTimeConverter dtConverter = new DateConverter();
dtConverter.setPattern("<your custom date pattern here>");
ConvertUtils.register(dtConverter, Date.class);

Done using this method:
public Object populate(Object obj, HashMap<String, String[]> formData)
throws IllegalAccessException, InvocationTargetException {
ConvertUtils
.register(new StringToDateConverter(), java.util.Date.class);
BeanUtilsBean.getInstance().populate(obj, formData);
return obj;
}

Related

AEM JAVA Unit test for tags

In AEM JAVA I created a function that gets a list of tags from Tag Manager . I was able to get the data that I need and the tags are correctly retrieved from the Tag Manager. But in the Unit Test this part below is always excluded from the test. I only included the code that is relevant to the question.
#SuppressWarnings("unchecked")
public Iterator<Resource> getTransform(Iterator<Tag> childTagItr, Locale locale, SlingHttpServletRequest request) {
return new TransformIterator(childTagItr, new Transformer() {
public Object transform(Object o) {
Tag tag = (Tag) o;
String tagId = tag.getTagID();
ValueMap vm = new ValueMapDecorator(new HashMap<String, Object>());
vm.put("value", tagId);
vm.put("text", tag.getTitlePath(locale));
return new ValueMapResource(request.getResourceResolver(), new ResourceMetadata(), "nt:unstructured", vm);
}
});
}
I tried with below test :
#Test
void testGetDataTags() throws ServletException, IOException {
// Arrange
Mockito.when(request.getAttribute(Mockito.anyString())).thenReturn(slingBindings);
Mockito.when(slingBindings.getSling()).thenReturn(sling);
Mockito.when(request.getResourceResolver()).thenReturn(resolver);
Mockito.when(request.getResourceResolver().adaptTo(TagManager.class)).thenReturn(tagManager);
//Mockito.when(config.get(PATH)).thenReturn(PATH);
//Mockito.when(expressionHelper.getString(PATH)).thenReturn(PATH_VALUE);
Mockito.when(tagManager.resolve(Mockito.anyString())).thenReturn(parentTag);
getTags();
// Act
final Locale locale = request.getLocale();
CareerPageCategoryLevelTwo careerPageCategoryLevelTwo = new CareerPageCategoryLevelTwo();
Transformer tagResource = new Transformer() {
public Object transform(Object o) {
Tag tag = (Tag) o;
String tagId = tag.getTagID();
ValueMap vm = new ValueMapDecorator(new HashMap<String, Object>());
vm.put("value", tagId);
vm.put("text", tag.getTitlePath(locale));
return new ValueMapResource(request.getResourceResolver(), new ResourceMetadata(), "nt:unstructured", vm);
}
};
#SuppressWarnings("unchecked")
Iterator<Resource> iteratorResource= new TransformIterator(tagIterator, tagResource);
Mockito.when(careerPageCategoryLevelTwo.getTransform(tagIterator, locale, request)).thenReturn(iteratorResource);
// Assert
assertNotNull(iteratorResource);
}
Still the part :
is excluded.
My question is how can I include this part in the Unit Test?
Update: careerPageCategoryLevelTwo is the implementation class
In your test method testGetDataTags you are mocking the method getTransform(). You are returning the iteratorResource instead of the "real" TransformIterator inside the class under test CareerPageCategoryLevelTwo.
You should change your line from
Mockito.when(careerPageCategoryLevelTwo.getTransform(tagIterator, locale request)).thenReturn(iteratorResource):
to
Iterator iteratorFromCareer = careerPageCategoryLevelTwo.getTransform(tagIterator, locale, request)
and you should do something with the iteratorFromCareer - this should call the transform method.
But I recommend you to use less Mockito and more Sling Mocks or AEM Mocks

Unparsable Date despite perfect format

I'm trying to parse a date departureTime:
String departureTime2, departureTime;
departureTime2 = departureTime = "2018-01-01 11:11:11.1";
Using the JUnit when method
when(bookingController.booking( departureTime, departureTime2).thenAnswer(new Answer<MockHttpSession>()
{
#Override
public MockHttpSession answer(InvocationOnMock invocation) throws Throwable
{
Object[] args = invocation.getArguments();
return (MockHttpSession) args[0];
}
});
My booking method in BookingController
#RequestMapping(value = "/bookingsingle", method = RequestMethod.POST)
public String bookingSingle(#RequestParam String departureTime,..)'
formats the date using
Date departureTimeAsDate = null;
DateFormat df = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss.S", Locale.ENGLISH);
try { departureTimeAsDate = df.parse(departureTime); } catch (ParseException e) { e.printStackTrace(); }
However I receive the error
java.text.ParseException: Unparseable date: "2018-01-01 11:11:11.1"
The date appears to be in the perfect format, and upon using the same code in a Java fiddle tool it compiles, however in intellij it runs into the error. Any suggestions would be appreciated.
EDIT:
I believe the problem may lie somewhere in the passing of the String in the when() method. Note that booking() has many irrelevant parameters I have excluded.

Parsing Json Dates with varying standards

I'm reading JSON data from an API using Jackson and most of the time I get an array of objects that are all fairly standard in their implementation. The only issue is that sometimes dates will be in the format "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" and sometimes in the format "yyyy-MM-dd", so the JSON looks like this:
[
{
'A':'Foo'
'B':'2016-11-03T12:35:23.032Z'
'C':'7'
},
{
'A':'Bar'
'B':'2016-11-06'
'C':'4'
},
{
'A':'Bla'
'B':'2016-11-07T14:42:18.832Z'
'C':'23'
},
{
'A':'Blo'
'B':'2016-11-07T15:12:23.439Z'
'C':'9'
}
]
Every time I get to that second date I get a parser error because it's not in the same format. I tried writing a class that will use a second DateFormat if the first one fails, but now I just get a NullPointerException.
public class BackupDateFormat extends DateFormat {
private final LinkedList<DateFormat> formats;
public BackupDateFormat(DateFormat... dfs) {
formats = new LinkedList<>(Arrays.asList(dfs));
}
#Override
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
return formats.getFirst().format(date, toAppendTo, fieldPosition);
}
#Override
public Date parse(String source, ParsePosition pos) {
return formats.getFirst().parse(source, pos);
}
#Override
public Date parse(String source) throws ParseException {
ParseException exception = null;
for (DateFormat df : formats) {
try {
return df.parse(source);
}
catch (ParseException pe) {
exception = pe;
}
}
throw exception;
}
}
His is the error I'm getting:
com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: com.company.api.API$Result["result"]->java.util.ArrayList[0]->com.company.models.othercompany.Record["dateTime"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:391)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:351)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1597)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:278)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:294)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:266)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:26)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:485)
at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:108)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:276)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3836)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2860)
at com.mentoredata.api.API.get(API.java:56)
This is the code at line 56:
return mapper.<List<T>>readValue(new URL(url), mapper.getTypeFactory().constructCollectionType(List.class, type));
Does anyone know how I can either fix my current code to not get a null pointer or use two dateformats in Jackson?
I'm having trouble telling exactly what your problem is, but I was able to get things working with the code you have. First, I created a POJO representing the object you are trying to deserialize. I'm kind of assuming you already have an equivalent, but this was mine:
class Obj {
String A;
Date B;
Integer C;
/* with getters/setters */
}
Then, I created a custom deserializer with the object mapper. The class is not too difficult to implement. I used your BackupDateFormat inside of the deserializer:
class ObjDeserializer extends JsonDeserializer<Obj> {
final BackupDateFormat backupDateFormat;
public ObjDeserializer() {
backupDateFormat = new BackupDateFormat(
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"),
new SimpleDateFormat("yyyy-MM-dd"));
}
#Override
public Obj deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
// create a POJO and populate with the fields from the JSON Object
Obj obj = new Obj();
JsonNode root = p.readValueAsTree();
obj.setA(root.get("A").asText(""));
obj.setC(root.get("C").asInt(0));
try {
obj.setB(backupDateFormat.parse(root.get("B").asText()));
} catch (ParseException e) {
throw new IOException("Could not parse date as expected.");
}
return obj;
}
}
After that, register your serializer with the ObjectMapper:
SimpleModule dateDeserializerModule = new SimpleModule();
// associate the custom deserializer with your POJO
dateDeserializerModule.addDeserializer(Obj.class, new ObjDeserializer());
mapper.registerModule(dateDeserializerModule);
Finally, you can see that the dates were appropriately parsed from this snippet and its output:
List<Obj> result = mapper.readValue(input.getBytes(), mapper.getTypeFactory().constructCollectionType(List.class, Obj.class));
result.forEach(x->System.out.println(x.getB().toString()));
Thu Nov 03 12:35:23 EDT 2016
Sun Nov 06 00:00:00 EDT 2016
Mon Nov 07 14:42:18 EST 2016
Mon Nov 07 15:12:23 EST 2016
If you find something built into Jackson that will do this, I encourage you to use it, but sometimes you end up needing the extra level of customization that this method provides. Hope it helps.
Check out the question below too. It's similar, but doesn't deal with multiple formats. The accepted answer uses the custom deserializer as well.
References:
Similar SO Question
Getting started with deserializers

In Android Studio I am getting errors with Java.text.DateFormat

I am trying to change the following code, to be better used in an Android environment as part of an upcoming API.
public class DateFormatter implement JsonDeserializer<Date>,
JsonSerializer<Date> {
private final DateFormat[] formats;
public DateFormatter() {
formats = new DateFormat[3];
formats[0] = new SimpleDateFormat(DATE_FORMAT);
formats[1] = new SimpleDateFormat(DATE_FORMAT_V2_1);
formats[2] = new SimpleDateFormat(DATE_FORMAT_V2_2);
final TimeZone timeZone = TimeZone.getTimeZone("Zulu"); //$NON-NLS-1$
for (DateFormat format : formats)
format.setTimeZone(timeZone);
}
public Date deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
JsonParseException exception = null;
final String value = json.getAsString();
for (DateFormat format : formats)
try {
synchronized (format) {
return format.parse(value);
}
} catch (ParseException e) {
exception = new JsonParseException(e);
}
throw exception;
}
public JsonElement serialize(Date date, Type type,
JsonSerializationContext context) {
final DateFormat primary = formats[0];
String formatted;
synchronized (primary) {
formatted = primary.format(date);
}
return new JsonPrimitive(formatted);
}
}
I do not need to support v2.1 and v2.2. so I've been trying to remove the array, and code it for just a single instance. I'm running into some errors though.
Here is what I have so far:
class DateFormatter implements JsonDeserializer<Date>,
JsonSerializer<Date> {
private DateFormat formats;
DateFormatter() {
formats = new DateFormat;
formats = new SimpleDateFormat(String.valueOf(R.string.date_format), Locale.ENGLISH);
final TimeZone timeZone = TimeZone.getTimeZone("Zulu");
for (DateFormat format : formats)
format.setTimeZone(timeZone);
}
public Date deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
JsonParseException exception = null;
final String value;
value = json.getAsString();
for (DateFormat format : formats)
try {
synchronized (format) {
return format.parse(value);
}
} catch (ParseException e) {
exception = new JsonParseException(e);
}
throw exception;
}
public JsonElement serialize(Date date, Type type,
JsonSerializationContext context) {
final DateFormat primary;
primary = formats;
String formatted;
synchronized (primary) {
formatted = primary.format(date);
}
return new JsonPrimitive(formatted);
}
}
However, once I get it this point, I get errors. The main one I'm currently concerned about is getString.
What am I doing wrong here?
Edit:
#trooper I am not able to build the project, so I can't pull a --stacktrace --debug
I changed the 2nd code block in the post to reflect my current code. I changed;
formats = new SimpleDateFormat(getString(R.string.date_format), Locale.ENGLISH);
to;
formats = new SimpleDateFormat(String.valueOf(R.string.date_format), Locale.ENGLISH);
and that corrected my first question.
So, now that is answered, moving on to my next question. As you can see I'm moving from an array in the first block to a single instance in the second. the line
for (DateFormat format : formats)
the "formats' is throwing a "foreach not applicable to java.text.DateFormat'
I know foreach is used in arrays, what I don't know is how to remove that part of the loop and achieve what i need to... this is where I get really lost.
My end goal is to Convert the current GitHib APIv3 written in Java for the Eclipse Studio which supports API v2 & v3, over to an Android GitHub API v3, seeing as we won't need to cover v2.
I hope this edit is enough information to be able to answer.
Formats is not declared as an array. You need to declare this as an array an initialize it one by one.
try this,
private final DateFormat[] formats
formats = new DateFormat[3];
formats[0] = new SimpleDateFormat(getString(R.string.date_format), Locale.ENGLISH);
to remove the loop just use
formats = new DateFormat;
formats = new SimpleDateFormat(String.valueOf(R.string.date_format), Locale.ENGLISH);
final TimeZone timeZone = TimeZone.getTimeZone("Zulu");
formats.setTimeZone(timeZone);

converting Document objects in MongoDB 3 to POJOS

I'm saving an object with a java.util.Date field into a MongoDB 3.2 instance.
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(myObject);
collection.insertOne(Document.parse(json));
the String contains:
"captured": 1454549266735
then I read it from the MongoDB instance:
final Document document = collection.find(eq("key", value)).first();
final String json = document.toJson();
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
xx = mapper.readValue(json, MyClass.class);
the deserialization fails:
java.lang.RuntimeException: com.fasterxml.jackson.databind.JsonMappingException:
Can not deserialize instance of java.util.Date out of START_OBJECT token
I see that the json string created by "document.toJson()" contains:
"captured": {
"$numberLong": "1454550216318"
}
instead of what was there originally ("captured": 1454549266735)
MongoDB docs say they started using "MongoDB Extended Json". I tried both Jackson 1 and 2 to parse it - no luck.
what is the easiest way to convert those Document objects provided by MongoDB 3 to Java POJOs? maybe I can skip toJson() step altogether?
I tried mongojack - that one does not support MongoDB3.
Looked at couple other POJO mappers listed on MongoDB docs page - they all require putting their custom annotations to Java classes.
You should define and use custom JsonWriterSettings to fine-tune JSON generation:
JsonWriterSettings settings = JsonWriterSettings.builder()
.int64Converter((value, writer) -> writer.writeNumber(value.toString()))
.build();
String json = new Document("a", 12).append("b", 14L).toJson(settings);
Will produce:
{ "a" : 12, "b" : 14 }
If you will not use custom settings then document will produce extended json:
{ "a" : 12, "b" : { "$numberLong" : "14" } }
This looks like Mongo Java driver bug, where Document.toJson profuces non-standard JSON even if JsonMode.STRICT is used. This problem is described in the following bug https://jira.mongodb.org/browse/JAVA-2173 for which I encourage you to vote.
A workaround is to use com.mongodb.util.JSON.serialize(document).
I save a tag with my mongo document that specifies the original type of the object stored. I then use Gson to parse it with the name of that type. First, to create the stored Document
private static Gson gson = new Gson();
public static Document ConvertToDocument(Object rd) {
if (rd instanceof Document)
return (Document)rd;
String json = gson.toJson(rd);
Document doc = Document.parse(json);
doc.append(TYPE_FIELD, rd.getClass().getName());
return doc;
}
then to read the document back into the Java,
public static Object ConvertFromDocument(Document doc) throws CAAException {
String clazzName = doc.getString(TYPE_FIELD);
if (clazzName == null)
throw new RuntimeException("Document was not stored in the DB or got stored without becing created by itemToStoredDocument()");
Class<?> clazz;
try {
clazz = (Class<?>) Class.forName(clazzName);
} catch (ClassNotFoundException e) {
throw new CAAException("Could not load class " + clazzName, e);
}
json = com.mongodb.util.JSON.serialize(doc);
return gson.fromJson(json, clazz);
}
Thanks to Aleksey for pointing out JSON.serialize().
It looks like you are using Date object inside "myObject". In that case, you should use a DateSerializer that implements JsonSerializer<LocalDate>, JsonDeserializer<LocalDate> and then register it with GsonBuilder. Sample code follows:
public class My_DateSerializer implements JsonSerializer<LocalDate>,
JsonDeserializer<LocalDate> {
#Override
public LocalDate deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
final String dateAsString = json.getAsString();
final DateTimeFormatter dtf = DateTimeFormat.forPattern(DATE_FORMAT);
if (dateAsString.length() == 0)
{
return null;
}
else
{
return dtf.parseLocalDate(dateAsString);
}
}
#Override
public JsonElement serialize(LocalDate src, Type typeOfSrc,
JsonSerializationContext context) {
String retVal;
final DateTimeFormatter dtf = DateTimeFormat.forPattern(DATE_FORMAT);
if (src == null)
{
retVal = "";
}
else
{
retVal = dtf.print(src);
}
return new JsonPrimitive(retVal);
}
}
Now register it with GsonBuilder:
final GsonBuilder builder = new GsonBuilder()
.registerTypeAdapter(LocalDate.class, new My_DateSerializer());
final Gson gson = builder.create();

Categories

Resources