I have an issue with some RESTful services that takes a transfer object in parameter (basically an XML object that will be unmarshalled to a POJO).
#XmlRootElement(name = "myPojo")
public class MyPojo {
#XmlElement(name = "myField")
private Boolean myBoolean;
public void setMyBoolean(Boolean bool) {
myBoolean = bool;
}
public Boolean getMyBoolean() {
return myBoolean;
}
}
And the service is something like that:
public class MyRestService {
#PUT
#Path("somewhere")
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response update(MyPojo pojo) {
System.out.println("Boolean value: " + pojo.getMyBoolean();
}
}
If I post this XML fragment:
<myPojo>
<myField>false</myField>
</myPojo>
I got:
Boolean value: false
And if I post this XML fragment:
<myPojo>
<myField>FALSE</myField>
</myPojo>
I got:
Boolean value: null
I run that code under Glassfish 4 with Jersey 1.9.1 and JAXB 2.2.7. In addition, under Glassfish 2, I got a different behavior where both uppercase and lowercase are unmarshalled as expected.
So, I am really curious to know what is happening and why the marshalling of boolean is different.
Thanks in advance
I run into the same problem today where JAXB returns null when parsing "FaLsE" or "True" on a Boolean field. Unfortunately, upgrading to 2.2.7 or above (2.2.11 as of today) didn't help me. When I dig deeper into the source code, it seems that the parsing logic happens inside DatatypeConverterImpl.java. And there is no configuration that can alter its behavior on uppercase.
Link to JAXB DatatypeConverterImpl.java
The solution that I found (and works), is to define a new BooleanAdapter and asks JAXB to use that instead. In the adapter, you can define whatever conversion logic that fits your application.
Custom BooleanAdapter.java
public class BooleanAdapter extends XmlAdapter<String, Boolean> {
#Override
public Boolean unmarshal(String v) throws Exception {
if (StringUtils.isBlank(v))
return null;
return Boolean.valueOf(v);
}
#Override
public String marshal(Boolean v) throws Exception {
if (v == null)
return null;
return v.toString();
}
}
Your model object
#XmlElement(name = "myField")
#XmlJavaTypeAdapter(BooleanAdapter.class)
public Boolean getMyBoolean() {
return myBoolean;
}
After several investigations, we figured out that the version 2.2 of JAXB we are using seems to contain a bug that serialize the boolean values not as expected. I mean that for example: FaLsE will be converted to null value.
Upgrading to the version 2.2.7 has fixed our issue.
Related
This might be a duplicate. But I cannot find a solution to my Problem.
I have a class
public class MyResponse implements Serializable {
private boolean isSuccess;
public boolean isSuccess() {
return isSuccess;
}
public void setSuccess(boolean isSuccess) {
this.isSuccess = isSuccess;
}
}
Getters and setters are generated by Eclipse.
In another class, I set the value to true, and write it as a JSON string.
System.out.println(new ObjectMapper().writeValueAsString(myResponse));
In JSON, the key is coming as {"success": true}.
I want the key as isSuccess itself. Is Jackson using the setter method while serializing? How do I make the key the field name itself?
This is a slightly late answer, but may be useful for anyone else coming to this page.
A simple solution to changing the name that Jackson will use for when serializing to JSON is to use the #JsonProperty annotation, so your example would become:
public class MyResponse implements Serializable {
private boolean isSuccess;
#JsonProperty(value="isSuccess")
public boolean isSuccess() {
return isSuccess;
}
public void setSuccess(boolean isSuccess) {
this.isSuccess = isSuccess;
}
}
This would then be serialised to JSON as {"isSuccess":true}, but has the advantage of not having to modify your getter method name.
Note that in this case you could also write the annotation as #JsonProperty("isSuccess") as it only has the single value element
I recently ran into this issue and this is what I found. Jackson will inspect any class that you pass to it for getters and setters, and use those methods for serialization and deserialization. What follows "get", "is" and "set" in those methods will be used as the key for the JSON field ("isValid" for getIsValid and setIsValid).
public class JacksonExample {
private boolean isValid = false;
public boolean getIsValid() {
return isValid;
}
public void setIsValid(boolean isValid) {
this.isValid = isValid;
}
}
Similarly "isSuccess" will become "success", unless renamed to "isIsSuccess" or "getIsSuccess"
Read more here: http://www.citrine.io/blog/2015/5/20/jackson-json-processor
Using both annotations below, forces the output JSON to include is_xxx:
#get:JsonProperty("is_something")
#param:JsonProperty("is_something")
When you are using Kotlin and data classes:
data class Dto(
#get:JsonProperty("isSuccess") val isSuccess: Boolean
)
You might need to add #param:JsonProperty("isSuccess") if you are going to deserialize JSON as well.
EDIT: If you are using swagger-annotations to generate documentation, the property will be marked as readOnly when using #get:JsonProperty. In order to solve this, you can do:
#JsonAutoDetect(isGetterVisibility = JsonAutoDetect.Visibility.NONE)
data class Dto(
#field:JsonProperty(value = "isSuccess") val isSuccess: Boolean
)
You can configure your ObjectMapper as follows:
mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
#Override
public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName)
{
if(method.hasReturnType() && (method.getRawReturnType() == Boolean.class || method.getRawReturnType() == boolean.class)
&& method.getName().startsWith("is")) {
return method.getName();
}
return super.nameForGetterMethod(config, method, defaultName);
}
});
I didn't want to mess with some custom naming strategies, nor re-creating some accessors.
The less code, the happier I am.
This did the trick for us :
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
#JsonIgnoreProperties({"success", "deleted"}) // <- Prevents serialization duplicates
public class MyResponse {
private String id;
private #JsonProperty("isSuccess") boolean isSuccess; // <- Forces field name
private #JsonProperty("isDeleted") boolean isDeleted;
}
Building upon Utkarsh's answer..
Getter names minus get/is is used as the JSON name.
public class Example{
private String radcliffe;
public getHarryPotter(){
return radcliffe;
}
}
is stored as { "harryPotter" : "whateverYouGaveHere" }
For Deserialization, Jackson checks against both the setter and the field name.
For the Json String { "word1" : "example" }, both the below are valid.
public class Example{
private String word1;
public setword2( String pqr){
this.word1 = pqr;
}
}
public class Example2{
private String word2;
public setWord1(String pqr){
this.word2 = pqr ;
}
}
A more interesting question is which order Jackson considers for deserialization. If i try to deserialize { "word1" : "myName" } with
public class Example3{
private String word1;
private String word2;
public setWord1( String parameter){
this.word2 = parameter ;
}
}
I did not test the above case, but it would be interesting to see the values of word1 & word2 ...
Note: I used drastically different names to emphasize which fields are required to be same.
You can change primitive boolean to java.lang.Boolean (+ use #JsonPropery)
#JsonProperty("isA")
private Boolean isA = false;
public Boolean getA() {
return this.isA;
}
public void setA(Boolean a) {
this.isA = a;
}
Worked excellent for me.
If you are interested in handling 3rd party classes not under your control (like #edmundpie mentioned in a comment) then you add Mixin classes to your ObjectMapper where the property/field names should match the ones from your 3rd party class:
public class MyStack32270422 {
public static void main(String[] args) {
ObjectMapper om3rdParty = new ObjectMapper();
om3rdParty .addMixIn(My3rdPartyResponse.class, MixinMyResponse.class);
// add further mixins if required
String jsonString = om3rdParty.writeValueAsString(new My3rdPartyResponse());
System.out.println(jsonString);
}
}
class MixinMyResponse {
// add all jackson annotations here you want to be used when handling My3rdPartyResponse classes
#JsonProperty("isSuccess")
private boolean isSuccess;
}
class My3rdPartyResponse{
private boolean isSuccess = true;
// getter and setter here if desired
}
Basically you add all your Jackson annotations to your Mixin classes as if you would own the class. In my opinion quite a nice solution as you don't have to mess around with checking method names starting with "is.." and so on.
there is another method for this problem.
just define a new sub-class extends PropertyNamingStrategy and pass it to ObjectMapper instance.
here is a code snippet may be help more:
mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
#Override
public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
String input = defaultName;
if(method.getName().startsWith("is")){
input = method.getName();
}
//copy from LowerCaseWithUnderscoresStrategy
if (input == null) return input; // garbage in, garbage out
int length = input.length();
StringBuilder result = new StringBuilder(length * 2);
int resultLength = 0;
boolean wasPrevTranslated = false;
for (int i = 0; i < length; i++)
{
char c = input.charAt(i);
if (i > 0 || c != '_') // skip first starting underscore
{
if (Character.isUpperCase(c))
{
if (!wasPrevTranslated && resultLength > 0 && result.charAt(resultLength - 1) != '_')
{
result.append('_');
resultLength++;
}
c = Character.toLowerCase(c);
wasPrevTranslated = true;
}
else
{
wasPrevTranslated = false;
}
result.append(c);
resultLength++;
}
}
return resultLength > 0 ? result.toString() : input;
}
});
The accepted answer won't work for my case.
In my case, the class is not owned by me. The problematic class comes from 3rd party dependencies, so I can't just add #JsonProperty annotation in it.
To solve it, inspired by #burak answer above, I created a custom PropertyNamingStrategy as follow:
mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
#Override
public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName)
{
if (method.getParameterCount() == 1 &&
(method.getRawParameterType(0) == Boolean.class || method.getRawParameterType(0) == boolean.class) &&
method.getName().startsWith("set")) {
Class<?> containingClass = method.getDeclaringClass();
String potentialFieldName = "is" + method.getName().substring(3);
try {
containingClass.getDeclaredField(potentialFieldName);
return potentialFieldName;
} catch (NoSuchFieldException e) {
// do nothing and fall through
}
}
return super.nameForSetterMethod(config, method, defaultName);
}
#Override
public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName)
{
if(method.hasReturnType() && (method.getRawReturnType() == Boolean.class || method.getRawReturnType() == boolean.class)
&& method.getName().startsWith("is")) {
Class<?> containingClass = method.getDeclaringClass();
String potentialFieldName = method.getName();
try {
containingClass.getDeclaredField(potentialFieldName);
return potentialFieldName;
} catch (NoSuchFieldException e) {
// do nothing and fall through
}
}
return super.nameForGetterMethod(config, method, defaultName);
}
});
Basically what this does is, before serializing and deserializing, it checks in the target/source class which property name is present in the class, whether it is isEnabled or enabled property.
Based on that, the mapper will serialize and deserialize to the property name that is exist.
I need help with Arquillian test.
Add code example of situation.
This code is working ok in real environment. Only in test case made with arquillian the result is not expected
The code:
#Stateless
public class CustomerResourceImpl implements CustomerResource{
#Override
public Response findOne(String id) {
String res = "Un cliente";
return Response.ok(res).build();
}
}
#Path("customer")
#Produces(MediaType.APPLICATION_JSON)
public interface CustomerResource {
#GET
#Path("/findOne")
public javax.ws.rs.core.Response findOne(#QueryParam("id") String id);
}
And this test case
#RunWith(Arquillian.class)
public class CustomerResourceTest {
#Deployment (testable = false)
public static Archive createTestArchive() {
return ShrinkWrap
..... (mas)
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
}
#ArquillianResource
private URL deploymentURL;
#Test
#RunAsClient
public void findOne(#ArquillianResteasyResource CustomerResource resource) throws Exception {
final Response response = resource.findOne("1");
System.out.println(response.getEntity()); // IS NULL ??
System.out.println(response.getStatus()); // 200 OK
assertNotNull(response);
}
}
The problem is that response.getEntity() is always NULL . Why? The status response OK = 200 , it is OK. This service run ok in jboss 7.2 with Java 8.
Thanks!
The reason is #Deployment (testable = false)
#Deployment says:
testable = Defines if this deployment should be wrapped up based on the protocol so the testcase can be executed incontainer.
So false means it will not be deployed in the container, and therefore will be null when your tests run inside the container.
I recommend using #Deployment with not parameters passed in rather than setting testable = true
I just solved this today after a days of fiddling. I think I pasted the #Deployment (testable = false) code from examples on the internet that I didn't understand hoping to get something working.
My (gradle 1.10 and gradle plugin 0.8)-based android project consists of a big android-library that is a dependency for 3 different android-apps
In my library, I would love to be able to use a structure like this
if (BuildConfig.SOME_FLAG) {
callToBigLibraries()
}
as proguard would be able to reduce the size of the produced apk, based on the final value of SOME_FLAG
But I can't figure how to do it with gradle as :
* the BuildConfig produced by the library doesn't have the same package name than the app
* I have to import the BuildConfig with the library package in the library
* The apk of an apps includes the BuildConfig with the package of the app but not the one with the package of the library.
I tried without success to play with BuildTypes and stuff like
release {
// packageNameSuffix "library"
buildConfigField "boolean", "SOME_FLAG", "true"
}
debug {
//packageNameSuffix "library"
buildConfigField "boolean", "SOME_FLAG", "true"
}
What is the right way to builds a shared BuildConfig for my library and my apps whose flags will be overridden at build in the apps?
As a workaround, you can use this method, which uses reflection to get the field value from the app (not the library):
/**
* Gets a field from the project's BuildConfig. This is useful when, for example, flavors
* are used at the project level to set custom fields.
* #param context Used to find the correct file
* #param fieldName The name of the field-to-access
* #return The value of the field, or {#code null} if the field is not found.
*/
public static Object getBuildConfigValue(Context context, String fieldName) {
try {
Class<?> clazz = Class.forName(context.getPackageName() + ".BuildConfig");
Field field = clazz.getField(fieldName);
return field.get(null);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
To get the DEBUG field, for example, just call this from your Activity:
boolean debug = (Boolean) getBuildConfigValue(this, "DEBUG");
I have also shared this solution on the AOSP Issue Tracker.
Update: With newer versions of the Android Gradle plugin publishNonDefault is deprecated and has no effect anymore. All variants are now published.
The following solution/workaround works for me. It was posted by some guy in the google issue tracker:
Try setting publishNonDefault to true in the library project:
android {
...
publishNonDefault true
...
}
And add the following dependencies to the app project that is using the library:
dependencies {
releaseCompile project(path: ':library', configuration: 'release')
debugCompile project(path: ':library', configuration: 'debug')
}
This way, the project that uses the library includes the correct build type of the library.
You can't do what you want, because BuildConfig.SOME_FLAG isn't going to get propagated properly to your library; build types themselves aren't propagated to libraries -- they're always built as RELEASE. This is bug https://code.google.com/p/android/issues/detail?id=52962
To work around it: if you have control over all of the library modules, you could make sure that all the code touched by callToBigLibraries() is in classes and packages that you can cleave off cleanly with ProGuard, then use reflection so that you can access them if they exist and degrade gracefully if they don't. You're essentially doing the same thing, but you're making the check at runtime instead of compile time, and it's a little harder.
Let me know if you're having trouble figuring out how to do this; I could provide a sample if you need it.
I use a static BuildConfigHelper class in both the app and the library, so that I can have the packages BuildConfig set as final static variables in my library.
In the application, place a class like this:
package com.yourbase;
import com.your.application.BuildConfig;
public final class BuildConfigHelper {
public static final boolean DEBUG = BuildConfig.DEBUG;
public static final String APPLICATION_ID = BuildConfig.APPLICATION_ID;
public static final String BUILD_TYPE = BuildConfig.BUILD_TYPE;
public static final String FLAVOR = BuildConfig.FLAVOR;
public static final int VERSION_CODE = BuildConfig.VERSION_CODE;
public static final String VERSION_NAME = BuildConfig.VERSION_NAME;
}
And in the library:
package com.your.library;
import android.support.annotation.Nullable;
import java.lang.reflect.Field;
public class BuildConfigHelper {
private static final String BUILD_CONFIG = "com.yourbase.BuildConfigHelper";
public static final boolean DEBUG = getDebug();
public static final String APPLICATION_ID = (String) getBuildConfigValue("APPLICATION_ID");
public static final String BUILD_TYPE = (String) getBuildConfigValue("BUILD_TYPE");
public static final String FLAVOR = (String) getBuildConfigValue("FLAVOR");
public static final int VERSION_CODE = getVersionCode();
public static final String VERSION_NAME = (String) getBuildConfigValue("VERSION_NAME");
private static boolean getDebug() {
Object o = getBuildConfigValue("DEBUG");
if (o != null && o instanceof Boolean) {
return (Boolean) o;
} else {
return false;
}
}
private static int getVersionCode() {
Object o = getBuildConfigValue("VERSION_CODE");
if (o != null && o instanceof Integer) {
return (Integer) o;
} else {
return Integer.MIN_VALUE;
}
}
#Nullable
private static Object getBuildConfigValue(String fieldName) {
try {
Class c = Class.forName(BUILD_CONFIG);
Field f = c.getDeclaredField(fieldName);
f.setAccessible(true);
return f.get(null);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
Then, anywhere in your library where you want to check BuildConfig.DEBUG, you can check BuildConfigHelper.DEBUG and access it from anywhere without a context, and the same for the other properties. I did it this way so that the library will work with all my applications, without needing to pass a context in or set the package name some other way, and the application class only needs the import line changed to suit when adding it into a new application
Edit: I'd just like to reiterate, that this is the easiest (and only one listed here) way to get the values to be assigned to final static variables in the library from all of your applications without needing a context or hard coding the package name somewhere, which is almost as good as having the values in the default library BuildConfig anyway, for the minimal upkeep of changing that import line in each application.
For the case where the applicationId is not the same as the package (i.e. multiple applicationIds per project) AND you want to access from a library project:
Use Gradle to store the base package in resources.
In main/AndroidManifest.xml:
android {
applicationId "com.company.myappbase"
// note: using ${applicationId} here will be exactly as above
// and so NOT necessarily the applicationId of the generated APK
resValue "string", "build_config_package", "${applicationId}"
}
In Java:
public static boolean getDebug(Context context) {
Object obj = getBuildConfigValue("DEBUG", context);
if (obj instanceof Boolean) {
return (Boolean) o;
} else {
return false;
}
}
private static Object getBuildConfigValue(String fieldName, Context context) {
int resId = context.getResources().getIdentifier("build_config_package", "string", context.getPackageName());
// try/catch blah blah
Class<?> clazz = Class.forName(context.getString(resId) + ".BuildConfig");
Field field = clazz.getField(fieldName);
return field.get(null);
}
use both
my build.gradle
// ...
productFlavors {
internal {
// applicationId "com.elevensein.sein.internal"
applicationIdSuffix ".internal"
resValue "string", "build_config_package", "com.elevensein.sein"
}
production {
applicationId "com.elevensein.sein"
}
}
I want to call like below
Boolean isDebug = (Boolean) BuildConfigUtils.getBuildConfigValue(context, "DEBUG");
BuildConfigUtils.java
public class BuildConfigUtils
{
public static Object getBuildConfigValue (Context context, String fieldName)
{
Class<?> buildConfigClass = resolveBuildConfigClass(context);
return getStaticFieldValue(buildConfigClass, fieldName);
}
public static Class<?> resolveBuildConfigClass (Context context)
{
int resId = context.getResources().getIdentifier("build_config_package",
"string",
context.getPackageName());
if (resId != 0)
{
// defined in build.gradle
return loadClass(context.getString(resId) + ".BuildConfig");
}
// not defined in build.gradle
// try packageName + ".BuildConfig"
return loadClass(context.getPackageName() + ".BuildConfig");
}
private static Class<?> loadClass (String className)
{
Log.i("BuildConfigUtils", "try class load : " + className);
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
private static Object getStaticFieldValue (Class<?> clazz, String fieldName)
{
try { return clazz.getField(fieldName).get(null); }
catch (NoSuchFieldException e) { e.printStackTrace(); }
catch (IllegalAccessException e) { e.printStackTrace(); }
return null;
}
}
For me this is the ONLY ONE AND ACCEPTABLE* SOLUTION TO determine the ANDROID APPLICATION BuildConfig.class:
// base entry point
// abstract application
// which defines the method to obtain the desired class
// the definition of the application is contained in the library
// that wants to access the method or in a superior library package
public abstract class BasApp extends android.app.Application {
/*
* GET BUILD CONFIG CLASS
*/
protected Class<?> getAppBuildConfigClass();
// HELPER METHOD TO CAST CONTEXT TO BASE APP
public static BaseApp getAs(android.content.Context context) {
BaseApp as = getAs(context, BaseApp.class);
return as;
}
// HELPER METHOD TO CAST CONTEXT TO SPECIFIC BASEpp INHERITED CLASS TYPE
public static <I extends BaseApp> I getAs(android.content.Context context, Class<I> forCLass) {
android.content.Context applicationContext = context != null ?context.getApplicationContext() : null;
return applicationContext != null && forCLass != null && forCLass.isAssignableFrom(applicationContext.getClass())
? (I) applicationContext
: null;
}
// STATIC HELPER TO GET BUILD CONFIG CLASS
public static Class<?> getAppBuildConfigClass(android.content.Context context) {
BaseApp as = getAs(context);
Class buildConfigClass = as != null
? as.getAppBuildConfigClass()
: null;
return buildConfigClass;
}
}
// FINAL APP WITH IMPLEMENTATION
// POINTING TO DESIRED CLASS
public class MyApp extends BaseApp {
#Override
protected Class<?> getAppBuildConfigClass() {
return somefinal.app.package.BuildConfig.class;
}
}
USAGE IN LIBRARY:
Class<?> buildConfigClass = BaseApp.getAppBuildConfigClass(Context);
if(buildConfigClass !- null) {
// do your job
}
*there are couple of things need to be watched out:
getApplicationContext() - could return a context which is not an App ContexWrapper implementation - see what Applicatio class extends & get to know of the possibilities of context wrapping
the class returned by final app could be loaded by different class loaders than those who will use it - depends of loader implementation and some principals typical (chierarchy, visibility) for loaders
everything depends on the implemmentation of as in this case simple DELEGATION!!! - the solution could be more sophisticetaded - i wanted only to show here the usage of DELEGATION pattern :)
** why i downwoted all of reflection based patterns because they all have weak points and they all in some certain conditions will fail:
Class.forName(className); - because of not speciified loader
context.getPackageName() + ".BuildConfig"
a) context.getPackageName() - "by default - else see b)" returns not package defined in manifest but application id (somtimes they both are the same), see how the manifest package property is used and its flow - at the end apt tool will replace it with applicaton id (see ComponentName class for example what the pkg stands for there)
b) context.getPackageName() - will return what the implementaio wants to :P
*** what to change in my solution to make it more flawless
replace class with its name that will drop the problems wchich could appear when many classes loaded with different loaders accessing / or are used to obtain a final result involving class (get to know what describes the equality between two classes (for a compiler at runtime) - in short a class equality defines not a self class but a pair which is constituted by the loader and the class. (some home work - try load a inner class with different loader and access it by outer class loaded with different loader) - it would turns out that we will get illegal access error :) even the inner class is in the same package has all modificators allowing access to it outer class :) compiler/linker "VM" treats them as two not related classes...
I have the following code with a simple class and a method for writing and then reading:
ObjectMapper mapper = new ObjectMapper();
try{
DataStore testOut = new DataStore();
DataStore.Checklist ch1 = testOut.addChecklist();
ch1.SetTitle("Checklist1");
String output = mapper.writeValueAsString(testOut);
JsonNode rootNode = mapper.readValue(output, JsonNode.class);
Map<String,Object> userData = mapper.readValue(output, Map.class);
}
public class DataStore {
public static class Checklist
{
public Checklist()
{
}
private String _title;
public String GetTitle()
{
return _title;
}
public void SetTitle(String title)
{
_title = title;
}
}
//Checklists
private Vector<Checklist> _checklists = new Vector<Checklist>();
public Checklist addChecklist()
{
Checklist ch = new Checklist();
ch.SetTitle("New Checklist");
_checklists.add(ch);
return ch;
}
public Vector<Checklist> getChecklists()
{
return _checklists;
}
public void setChecklists(Vector<Checklist> checklists)
{
_checklists = checklists;
}
}
The line:
String output = mapper.writeValueAsString(testOut);
causes an exception that has had me baffled for hours and about to abandon using this at all.
Any hints are appreciated.
Here is the exception:
No serializer found for class DataStore$Checklist and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: DataStore["checklists"]->java.util.Vector[0])
There are multiple ways to do it, but I will start with what you are doing wrong: your naming of getter and setter method is wrong -- in Java one uses "camel-case", so you should be using "getTitle". Because of this, properties are not found.
Besides renaming methods to use Java-style names, there are alternatives:
You can use annotation JsonProperty("title") for GetTitle(), so that property is recognized
If you don't want the wrapper object, you could alternatively just add #JsonValue for GetTitle(), in which case value used for the whole object would be return value of that method.
The answer seems to be: You can't do that with Json. I've seen comments in the Gson tutorial as well, that state that some serialization just doesn't work. I downloaded XStream and spat it out with XML in a few minutes of work and a lot less construction around what I really wanted to persist. In the process, I was able to delete a lot of code.
I'm using a HeaderColumnNameMappingStrategy to map a csv file with a header into a JavaBean. String values parse fine but any "true" or "false" value in csv doesn't map to JavaBean and I get the following exception from the PropertyDescriptor:
java.lang.IllegalArgumentException: argument type mismatch
The code where it occurs is in CsvToBean, line 64:
protected T processLine(MappingStrategy<T> mapper, String[] line) throws
IllegalAccessException, InvocationTargetException, InstantiationException, IntrospectionException {
T bean = mapper.createBean();
for(int col = 0; col < line.length; col++) {
String value = line[col];
PropertyDescriptor prop = mapper.findDescriptor(col);
if (null != prop) {
Object obj = convertValue(value, prop);
// this is where exception is thrown for a "true" value in csv
prop.getWriteMethod().invoke(bean, new Object[] {obj});
}
}
return bean;
}
protected PropertyEditor getPropertyEditor(PropertyDescriptor desc) throws
InstantiationException, IllegalAccessException {
Class<?> cls = desc.getPropertyEditorClass();
if (null != cls) return (PropertyEditor) cls.newInstance();
return getPropertyEditorValue(desc.getPropertyType());
}
I can confirm (via debugger) that the setter method id correctly retrieved at this point.
The problem occurs in desc.getPropertyEditorClass() since it returns null. I assumed primitive types and its wrappers are supported. Are they not?
I've run into this same issue. The cleanest way is probably to override getPropertyEditor like pritam did above and return a custom PropertyEditor for your particular object. The quick and dirty way would be to override convertValue in anonymous class form, like this:
CsvToBean<MyClass> csvToBean = new CsvToBean<MyClass>(){
#Override
protected Object convertValue(String value, PropertyDescriptor prop) throws InstantiationException,IllegalAccessException {
if (prop.getName().equals("myWhatever")) {
// return an custom object based on the incoming value
return new MyWhatever((String)value);
}
return super.convertValue(value, prop);
}
};
This is working fine for me with OpenCSV 2.3. Good luck!
I resolved this by extending CsvToBean and adding my own PropertyEditors. Turns out opencsv just supports primitive types and no wrappers.
Pritam's answer is great and this is a sample for dealing with datetime format.
PropertyEditorManager.registerEditor(java.util.Date.class, DateEditor.class);
You should write your own editor class like this:
public class DateEditor extends PropertyEditorSupport{
public static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
#Override
public void setAsText(String text){
setValue(sdf.parse(text));}
}