Help please, I get the following message, in the following code that I have:
listaFinal = (ArrayList<PuntoNota>) getIntent().getSerializableExtra("miLista");
AdapterDatos adapter = new AdapterDatos(this, listaFinal);
PuntoNota.java
public class PuntoNota implements Serializable{
private String punto;
private String nota;
public PuntoNota (String punto, String nota){
this.punto = punto;
this.nota = nota;
}
public String getPunto(){
return punto;
}
public String getNota(){
return nota;
}
}
AdapterDatos:
public AdapterDatos(Context context, ArrayList<PuntoNota> puntoNotaList) {
this.context = context;
this.puntoNotaList = puntoNotaList;
}
The application is working well, but I get the following message:
Unchecked cast: 'java.io.Serializable' to 'java.util.ArrayList ' less ... (Ctrl + F1).
about this code: (ArrayList ) getIntent (). getSerializableExtra ("myList"); will it be advisable to delete or hide this message?
Root cause: This is a warning from IDE, getSerializableExtra return a Serializable, and you are trying to convert to ArrayList<PuntoNota>. It might throw ClassCastException at runtime if the programe cannot cast it to your expected type.
Solution: In android to pass a user-defined object around, your class should implements Parcelable instead of Serializable interface.
class PuntoNota implements Parcelable {
private String punto;
private String nota;
public PuntoNota(String punto, String nota) {
this.punto = punto;
this.nota = nota;
}
protected PuntoNota(Parcel in) {
punto = in.readString();
nota = in.readString();
}
public String getPunto() {
return punto;
}
public String getNota() {
return nota;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(punto);
dest.writeString(nota);
}
public static final Creator<PuntoNota> CREATOR = new Creator<PuntoNota>() {
#Override
public PuntoNota createFromParcel(Parcel in) {
return new PuntoNota(in);
}
#Override
public PuntoNota[] newArray(int size) {
return new PuntoNota[size];
}
};
}
At sender side
ArrayList<PuntoNota> myList = new ArrayList<>();
// Fill data to myList here
...
Intent intent = new Intent();
intent.putParcelableArrayListExtra("miLista", myList);
At receiver side
ArrayList<? extends PuntoNota> listaFinal = getIntent().getParcelableArrayListExtra("miLista");
You can set a warning Suppression #SuppressWarnings annotation.
Example:
#SuppressWarnings("unchecked")
listaFinal = (ArrayList<PuntoNota>) getIntent().getSerializableExtra("miLista");
It is an annotation to suppress compile warnings about unchecked generic operations (not exceptions), such as casts. It essentially implies that the programmer did not wish to be notified about these which he is already aware of when compiling a particular bit of code.
You can read more on this specific annotation here:
SuppressWarnings
Additionally, Oracle provides some tutorial documentation on the usage of annotations here:
Annotations
As they put it,
"The 'unchecked' warning can occur when interfacing with legacy code written before the advent of generics (discussed in the lesson titled Generics)."
Related
I got an error as below:
Error:(133, 15) error: method setMonkeyBuisness in class QuoteBank cannot be applied to given types;
required: ArrayList<QuoteQuestion>
found: ArrayList<Parcelable>
reason: actual argument ArrayList<Parcelable> cannot be converted to
ArrayList<QuoteQuestion> by method invocation conversion
Both QuoteQuestion and QuoteBank implement Parcelable and all their methods. I cannot type cast parcelable either.
Am I using Parcelable array list correctly?
Here is some part of my code for QuoteBank:
public class QuoteBank implements Parcelable{
public static final String ARRAY_LIST_KEY = "arrayListKey";
private ArrayList<QuoteQuestion> monkeyBuisness;
public QuoteBank(){
}
#Override
public void writeToParcel(Parcel dest, int flags) {
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(ARRAY_LIST_KEY, monkeyBuisness);
dest.writeBundle(bundle);
}
public static final Parcelable.Creator<QuoteBank> CREATOR = new Creator<QuoteBank>() {
#Override
public QuoteBank createFromParcel(Parcel source) {
Bundle bundle = source.readBundle();
QuoteBank qb = new QuoteBank();
qb.setMonkeyBuisness(bundle.getParcelableArrayList(ARRAY_LIST_KEY));
return qb;
}
public void setMonkeyBuisness(ArrayList<QuoteQuestion> monkeyBuisness) {
this.monkeyBuisness = monkeyBuisness;
}
Here is QuoteQuestion code:
public class QuoteQuestion implements Parcelable{
public static final String QUOTE_TYPE = "quoteType";
public static final String QUOTE_NUMBER = "quoteNumber";
public static final String QUOTE_ARRAY = "quoteArray";
public static final String SPEAKER_ARRAY = "speakerArray";
public static final String ANSWER_INDEX_ARRAY = "answerIndexArray";
public static final String ANSWER_CHOICE_ARRAY = "answerChoiceArray";
public static final String CONTEXT_KEY = "contextKey";
public static final String CHOSEN_ANSWER = "chosenAnswer";
public static final String WORD_SPLIT = "wordSplit";
private int quoteNumber;
private String quoteType;
private ArrayList<String> quote;
private ArrayList<String> speaker;
private ArrayList<Integer> answerIndex;
private ArrayList<String> answerChoice;
private String context;
private String chosenAnswer;
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
Bundle bundle = new Bundle();
// insert the key value pairs to the bundle
bundle.putInt(QUOTE_NUMBER, quoteNumber);
bundle.putString(QUOTE_TYPE, quoteType);
bundle.putStringArrayList(QUOTE_ARRAY, quote);
bundle.putStringArrayList(SPEAKER_ARRAY, speaker);
bundle.putIntegerArrayList(ANSWER_INDEX_ARRAY, answerIndex);
bundle.putStringArrayList(ANSWER_CHOICE_ARRAY, answerChoice);
bundle.putString(CONTEXT_KEY, context);
bundle.putString(CHOSEN_ANSWER, chosenAnswer);
bundle.putStringArrayList(WORD_SPLIT, wordSplitTypeA);
// write the key value pairs to the parcel
dest.writeBundle(bundle);
}
public static final Parcelable.Creator<QuoteQuestion> CREATOR = new Creator<QuoteQuestion>() {
#Override
public QuoteQuestion createFromParcel(Parcel source) {
// read the bundle containing key value pairs from the parcel
Bundle bundle = source.readBundle();
QuoteQuestion quoteQuestion = new QuoteQuestion();
quoteQuestion.setQuoteNumber(bundle.getInt(QUOTE_NUMBER));
quoteQuestion.setQuoteType(bundle.getString(QUOTE_TYPE));
quoteQuestion.setQuote(bundle.getStringArrayList(QUOTE_ARRAY));
quoteQuestion.setSpeaker(bundle.getStringArrayList(SPEAKER_ARRAY));
quoteQuestion.setAnswerIndex(bundle.getIntegerArrayList(ANSWER_INDEX_ARRAY));
quoteQuestion.setAnswerChoice(bundle.getStringArrayList(ANSWER_CHOICE_ARRAY));
quoteQuestion.setContext(bundle.getString(CONTEXT_KEY));
quoteQuestion.setChosenAnswer(bundle.getString(CHOSEN_ANSWER));
quoteQuestion.setWordSplitTypeA(bundle.getStringArrayList(WORD_SPLIT));
return quoteQuestion;
}
#Override
public QuoteQuestion[] newArray(int size) {
return new QuoteQuestion[size];
}
};
Also I have a second question while here - It seems all big multi UI apps will have almost all classes implement parcelable? as it is the only way to get data around the app? Is this best practice?
Split your statement into two, using a variable to hold the properly-typed ArrayList, like this:
ArrayList<QuoteQuestion> qq = bundle.getParcelableArrayList(ARRAY_LIST_KEY);
qb.setMonkeyBuisness(qq);
Why this works, whereas casting does not? I have no idea. If anyone knows, please replace this paragraph!
As for the second question, about implementing Parcelable all over the place: The temporary-by-design nature of all Activities and heavy usage of Intents can lead to requiring Parcelable in many places. Certain app design patterns can help mitigate the problem. For example, following MVC techniques, your application data can live within the Model, accessible via a custom class derived from Application. This allows most Activities to avoid saving & restoring bundled data, as they are simply Views of the Model, which persists across device rotations etc. This is a much bigger topic of course, with many different approaches, but hopefully this sparks some ideas.
It should suffice to write:
qb.setMonkeyBuisness(bundle.<QuoteQuestion>getParcelableArrayList(ARRAY_LIST_KEY));
Running into a maddening blocking error:
Exception in thread "main" java.lang.Error: Structure.getFieldOrder() on class com.luke.generator.GeneratorEngine$VERSION_INFO returns names ([BuildString, ProtocolMajorVer, ProtocolMinorVer]) which do not match declared field names ([BiuldString, ProtocolMajorVer, ProtocolMinorVer])
at com.sun.jna.Structure.getFields(Structure.java:925)
at com.sun.jna.Structure.deriveLayout(Structure.java:1058)
at com.sun.jna.Structure.calculateSize(Structure.java:982)
at com.sun.jna.Structure.calculateSize(Structure.java:949)
at com.sun.jna.Structure.allocateMemory(Structure.java:375)
at com.sun.jna.Structure.<init>(Structure.java:184)
at com.sun.jna.Structure.<init>(Structure.java:172)
at com.sun.jna.Structure.<init>(Structure.java:159)
at com.sun.jna.Structure.<init>(Structure.java:151)
at com.luke.generator.GeneratorEngine$.<init>(GeneratorEngine.java:108)
at com.luke.generator.connectionVersion(GeneratorEngine.java:297)
at com.luke.generator.Main.main(Main.java:161)
Platform: Intel, Windows 8
JRE 1.7, 32-bit (x86)
Eclipse Kepler, Default encoding UTF-8
jna-4.1.0.jar
32-bit CPP DLL - I can confirm that I am loading the library and calling functions that do not include parameters. I also tried passing WStrings and Strings, but that did not address the issue.
Source:
CPP struct:
typedef struct {
UINT32 ProtocolMajorVer;
UINT32 ProtocolMinorVer;
UI_STRING BuildString; // Build version for the application.
} VERSION_INFO;
CPP Function
DLL_EXPORTS RETURN_TYPES ConnectionVersion (VERSION_INFO &Version) {<body omitted>}
Java code:
//Interface definition
public interface UiApi extends StdCallLibrary {
UiApi INSTANCE = (UiApi) Native.loadLibrary(UiApiPath,UiApi.class);
final String PROTOCOLMAJORVERSION = new String("ProtocolMajorVer");
final String PROTOCOLMINORVERSION = new String("ProtocolMinorVer");
final String BUILDSTRING = new String("BuildString");
public static class VERSION_INFO extends Structure {
public static class ByReference extends VERSION_INFO implements Structure.ByReference {}
public static class ByValue extends VERSION_INFO implements Structure.ByValue {}
public int ProtocolMajorVer;
public int ProtocolMinorVer;
public byte[] BiuldString;
protected List getFieldOrder() {
return Arrays.asList(new String[] { "ProtocolMajorVer","ProtocolMinorVer","BuildString" });
}
}
//Connection
public int Connect(byte[] strServerName);
public int Disconnect();
public int CloseProject();
public int ConnectionVersion(VERSION_INFO result);
public int ConnectionVersion(VERSION_INFO.ByReference result);
public int ConnectionVersion(VERSION_INFO.ByValue result);
}
//Engine.connectionVersion() method
public static int connectionVersion() {
int nReturn = 0;
String str = new String("This is my build version\n");
UiApi uiapilib;
uiapilib = UiApi.INSTANCE;
try {
UiApi.VERSION_INFO.ByReference result = new UiApi.VERSION_INFO.ByReference();
result.ProtocolMajorVer = 0;
result.ProtocolMinorVer = 0;
result.BiuldString = str.getBytes();
nReturn = uiapilib.ConnectionVersion(result);
}
catch (Exception e) {
System.out.println("Error=" + e.getLocalizedMessage());
}
return nReturn;
}
//This is the code in main that results in exception
private static Engine engine;
engine = new GeneratorEngine();
engine.connectionVersion();
I must be missing something basic. Is there something in Eclipse that could possibly be causing the HashSet name comparisons in JNA's Structure.java (line 925) that would result in names not matching? From the exception thrown, these definitions look identical.
Thanks for any tips, guidance, fresh perspectives you can offer.
Check your spelling - the field is called BiuldString not BuildString, you have the i and u reversed.
I have some class storing keys with important information. No one else is allowed to create a key, since a key relys on static information (like certain directory structures etc.).
public final class KeyConstants
{
private KeyConstants()
{
// could throw an exception to prevent instantiation
}
public static final Key<MyClass> MY_CLASS_DATA = new Key<MyClass>("someId", MyClass.class);
public static class Key<T>
{
public final String ID;
public final Class<T> CLAZZ;
private Key(String id, Class<T> clazz)
{
this.ID = id;
this.CLAZZ = clazz;
}
}
}
This example is simplyfied.
I wanted to test the consequences of a wrong key (exception handling, etc.) and instantiated the class via reflection in a JUnit test case.
Constructor<?> c = KeyConstants.Key.class.getDeclaredConstructor(String.class, Class.class);
c.setAccessible(true);
#SuppressWarnings ("unchecked")
KeyConstants.Key<MyClass> r = (KeyConstants.Key<MyClass>) c.newInstance("wrongId", MyClass.class);
Then I asked myself how could I prevent further instantiation of the key class (i. e. preventing further object creating via reflection)?
enums came to my mind, but they don't work with generics.
public enum Key<T>
{
//... Syntax error, enum declaration cannot have type parameters
}
So how can I keep a set of n instances of a generic class and prevent further instantiation?
So how can I keep a set of n instances of a generic class and prevent
further instantiation?
If you truly want to use this pattern, then no one (including you) should be able to instantiate a Key object. In order to keep a set of n instances in a class with this pattern, you could have a private constructor, a static method for access and a SecurityManager to prevent reflection. And since you want to be able to access the keys as pubic constants, I would try something like this..
public class KeyConstants{
// Here are your n instances for public access
public static final int KEY_1 = 1;
public static final int KEY_2 = 2;
.
.
.
public static final int KEY_N = 'n';
// now you can call this method like this..
// Key mKey = KeyConstants.getKey(KeyConstants.KEY_1);
public static Key getKey(int key){
List keys = Key.getInstances();
switch(key){
case KEY_1:
return keys.get(0);
case KEY_2:
return keys.get(1);
.
.
.
case KEY_N:
return keys.get(n);
default:
// not index out of bounds.. this means
// they didn't use a constant
throw new IllegalArgumentException();
}
}
static class Key<T>{
private static List<Key> instances;
private String ID;
private Class<T> CLAZZ;
private Key(String id, Class<T> clazz){
this.ID = id;
this.CLAZZ = clazz;
}
public static List<Key> getInstances(){
if(instances == null){
instances = new ArrayList<Key>();
//populate instances list
}
return instances;
}
}
}
Use SecurityManager to prevent reflection access.
//attempt to set your own security manager to prevent reflection
try {
System.setSecurityManager(new MySecurityManager());
} catch (SecurityException se) {
}
class MySecurityManager extends SecurityManager {
public void checkPermission(Permission perm) {
if (perm.getName().equals("suppressAccessChecks"))
throw new SecurityException("Invalid Access");
}
}
This will throw a SecurityException anytime someone attempts to access a private variable or field in your class (including access attempts via reflection).
I'm not sure I fully understand your question, but if a private constructor is not sufficient, can you use a more dynamic approach and throw an exception in the constructor after a signal is given? For example:
public static class Key<T>
{
private static boolean isLocked = false;
// Call this method when you want no more keys to be created
public static void lock() { isLocked = true; }
...
private Key(String id, Class<T> clazz)
{
if (isLocked) throw new IllegalStateException("Cannot create instances of Key");
this.ID = id;
this.CLAZZ = clazz;
}
}
Then - and this is the disadvantage - you will have to call Key.lock() once you want to prevent more instances being created.
As you showed in your code to prevent instantiating KeyConstants you can throw some Exception inside private-non-argument constructor.
Harder part is way to block creating KeyConstants.Key constructor from outside of KeyConstants class.
Some wild idea
Maybe create Exception in your constructor and check how its stack trace looks like. When I add this code to constructor
private Key(String id, Class<T> clazz) {
StackTraceElement[] stack = new Exception().getStackTrace();
for (int i=0; i<stack.length; i++){
System.out.println(i+") "+stack[i]);
}
this.ID = id;
this.CLAZZ = clazz;
}
and create instance of Key with reflection like
Constructor<?> c = KeyConstants.Key.class.getDeclaredConstructor(
String.class, Class.class);
c.setAccessible(true);
KeyConstants.Key<MyClass> r = (KeyConstants.Key<MyClass>) c
.newInstance("wrongId", MyClass.class);
I get
0) KeyConstants$Key.<init>(Test.java:38)
1) sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
2) sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
3) sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
4) java.lang.reflect.Constructor.newInstance(Constructor.java:525)
so maybe just if 4th element of stack is java.lang.reflect.Constructor.newInstance throw Exception to prevent executing rest of constructors code like:
if (stack.length>=4 && stack[4].toString().startsWith("java.lang.reflect.Constructor.newInstance")){
throw new RuntimeException("cant create object with reflection");
}
I came across some Multiton patterns recently, where I tried to handle problems with unique enum keys, that gave me the idea of another approach.
The keys can be used for information flow as I intended, or even as keys for typesafe heterogeneous container, where they can perform compile-time casting.
Key-defining class
public class KeyConstants
{
public static final KeysForIntegers SOME_INT_KEY = KeysForIntegers.KEY_2;
public static final KeysForStrings SOME_STRING_KEY = KeysForStrings.KEY_1;
public interface Key<Type>
{
public Class<Type> getType();
}
/* Define methods that classes working with the keys expect from them */
public interface KeyInformation
{
public String getInfo1();
// and so on...
}
public enum KeysForStrings implements Key<String>, KeyInformation
{
KEY_1("someId");
public final String ID;
private KeysForStrings(String id)
{
ID = id;
}
#Override
public String getInfo1()
{
return "Good piece of information on " + ID + ".";
}
#Override
public Class<String> getType()
{
return String.class;
}
}
public enum KeysForIntegers implements Key<Integer>, KeyInformation
{
KEY_2("bla");
public final String ID;
private KeysForIntegers(String id)
{
this.ID = id;
}
#Override
public String getInfo1()
{
return "Some info on " + ID + ".";
}
#Override
public Class<Integer> getType()
{
return Integer.class;
}
}
}
Example key-using class
public class KeyUser
{
public static void main(String[] args)
{
KeysForIntegers k1 = KeyConstants.SOME_INT_KEY;
KeysForStrings k2 = KeyConstants.SOME_STRING_KEY;
processStringKey(k2);
useIntKey(k1);
Integer i = useIntKey(KeyConstants.SOME_INT_KEY);
processStringKey(KeyConstants.SOME_STRING_KEY);
}
/* My methods should just work with my keys */
#SuppressWarnings ("unchecked")
public static <TYPE, KEY extends Enum<KeysForIntegers> & Key<TYPE> & KeyInformation> TYPE useIntKey(KEY k)
{
System.out.println(k.getInfo1());
return (TYPE) new Object();
}
public static <KEY extends Enum<KeysForStrings> & KeyInformation> void processStringKey(KEY k)
{
System.out.println(k.getInfo1());
// process stuff
}
}
I have another approach, you can bound an interface in a way to only be implemented by enum.
With that approach you have a fixed set of instances at compile time.
If you want to add lazy loading, the enums implementing it should be proxies that load the desired object if it is requested. The class or classes that are hidden behind the proxies should only be visible to them, so that they have exclusive access to the constructor.
public class User {
public static <S> S handleKey(FixedInstanceSet<S,?> key) {
return key.getKey();
}
}
interface FixedInstanceSet<S, T extends Enum<T> & FixedInstanceSet<S,T>>
{
public S getKey();
}
enum StringKeys implements FixedInstanceSet<String, StringKeys> {
TOP, DOWN, LEFT, RIGHT;
#Override
public String getKey() { return null; }
}
enum IntKeys implements FixedInstanceSet<Integer, IntKeys > {
TOP, DOWN, LEFT, RIGHT;
#Override
public Integer getKey() { return null; }
}
/*
* Bound mismatch: The type NotWorking is not a valid substitute for the bounded
* parameter <T extends Enum<T> & FixedInstanceSet<S,T>> of the type
* FixedInstanceSet<S,T>
*/
//class NotCompiling implements FixedInstanceSet<String, NotCompiling> {
//
// #Override
// public String getKey() { return null; }
//}
If I understand you correctly, you don't want your class to be instantiated.
You can set the default constructor to private
private Key() throws IllegalStateException //handle default constructor
{
throw new IllegalStateException();
}
This will prevent its improper instantiation.
Update:
added throw IllegalStateException
This question already has answers here:
What causes javac to issue the "uses unchecked or unsafe operations" warning
(12 answers)
Closed 3 years ago.
I want to make a generic container class that can contain one object of some other class. I thought this might be a reasonable approach:
class Container <T> {
private T thing;
public void Store(T obj) {
thing = obj;
}
public T ReturnIt() {
return thing;
}
}
When I try this together with let's say a Book class, I get the following error message:
"Note: GenericContainer.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details."
Could it be that the public T ReturnIt() { return thing; } is the cause of the error, and is this the wrong way to go about returning object that is contained in the Container-class?
I did not get any further information when I tried to compile it with -Xlint:unchecked.
What do I make of the error message?
Code that caused the error:
class GenericContainer {
public static void main(String[] args) {
Container BookStorage = new Container <Book>();
Book thejavabook = new Book("The Java book");
BookStorage.Store(thejavabook);
}
}
class Book {
private String title;
Book(String title) {
this.title = title;
}
}
class Container <T> {
private T thing;
public void Store(T obj) {
thing = obj;
}
public T ReturnIt() {
return thing;
}
}
Your BookStorage variable should be defined like this:
Container<Book> BookStorage = new Container <Book>();
I've rewritten your code to fix the problem and to use java naming standards:
package com.sandbox;
public class Sandbox {
public static void main(String[] args) {
Container<Book> bookStorage = new Container<Book>(); //fix for your warning!
Book theJavaBook = new Book("The Java book");
bookStorage.store(theJavaBook);
}
}
class Book {
private String title; //this is unused
Book(String title) {
this.title = title;
}
}
class Container<T> {
private T thing;
public void store(T obj) {
thing = obj;
}
public T returnIt() {
return thing;
}
}
Emphasis on this line:
Container<Book> bookStorage = new Container<Book>(); //fix for your warning!
You forgot to put the <Book> on the left hand side of your assignment.
I am currently working with XML files, and am searching to have a better way to avoid try/catch blocks in a nice way.
Here is the thing. Let's say I have an XML file.
<A>
<BB>37</BB>
<CC>
<DDD>1</DDD>
</CC>
</A>
In fact, I turn this into an object, which means that I can do
myXml.getA() and so on.
In my code, I search a lot for given elements in this object, which means that I have a lot of lines like
int ddd = myXml.getA().getCC().getDDD();
The thing is that some elements may not be there, and for example another XML element can be like that only :
<A'>
<BB'>37</BB'>
</A'>
So if I try to get ddd, getCC() raises a NullPointerException.
In the end, I end up coding it like that :
int ddd;
try{
ddd = myXml.getA().getCC().getDDD();
}
catch (NullPointerException e){
ddd = 0;
}
This works but the code becomes really ugly.
I am searching for a solution to have something like
int ddd = setInt(myXml.getA().getCC().getDDD(), 0);
0 being the default in case the method raises an exception.
Is there a nice way to do that ?
Up to now, I couldn't find a solution that do not raise errors.
Thx for your help !
EDIT: Just not to get XML related answers.
I showed the xml part for everybody to understand the problem.
In my code, I don't have access to the XML, but only the object that represents it.
To make it short, what I'd really love is some kind of isNull method to test my getters.
This is sort of an annoyance of working with jaxb. in my company, we do enough work with jaxb that it was worth writing an xjc plugin which generated "safe" versions of every getter that were guaranteed to return non-null values for any non-trivial value (immutable instances in the case that a sub-object did not really exist).
Here's an example of what our generated model entities look like:
public class ExampleUser implements Serializable {
private final static long serialVersionUID = 20090127L;
#XmlAttribute
protected String name;
#XmlAttribute
protected String email;
public final static ExampleUser EMPTY_INSTANCE = new ExampleUser() {
private static final long serialVersionUID = 0L;
#Override
public void setName(java.lang.String value) { throw new UnsupportedOperationException(); }
#Override
public void setEmail(java.lang.String value) { throw new UnsupportedOperationException(); }
};
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
public String getEmail() {
return email;
}
public void setEmail(String value) {
this.email = value;
}
}
public class ExampleAccount implements Serializable {
private final static long serialVersionUID = 20090127L;
protected ExampleUser user;
#XmlElement(name = "alias")
protected List<String> aliases;
#XmlAttribute
protected String id;
#XmlAttribute
protected String name;
public final static ExampleAccount EMPTY_INSTANCE = new ExampleAccount() {
private static final long serialVersionUID = 0L;
#Override
public void setUser(com.boomi.platform.api.ExampleUser value) { throw new UnsupportedOperationException(); }
#Override
public List<String> getAliases() { return java.util.Collections.emptyList(); }
#Override
public void setId(java.lang.String value) { throw new UnsupportedOperationException(); }
#Override
public void setName(java.lang.String value) { throw new UnsupportedOperationException(); }
};
public ExampleUser getUser() {
return user;
}
public void setUser(ExampleUser value) {
this.user = value;
}
public List<String> getAliases() {
if (aliases == null) {
aliases = new ArrayList<String>();
}
return this.aliases;
}
public String getId() {
return id;
}
public void setId(String value) {
this.id = value;
}
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
public ExampleUser safeGetUser() {
return (getUser() != null) ? getUser() : ExampleUser.EMPTY_INSTANCE;
}
}
So you could write this code without fear of NPE:
userEmail = account.safeGetUser().getEmail();
You can look at the Null objec pattern.
For example :
public class A {
private C c;
public C getC() {
if (c == null) {
c = new C(0); // the "null object"
}
return c;
}
}
public class C {
private int d;
public C(int d) {
this.d = d;
}
public int getD() {
return d;
}
}
But personnaly, i have a bad feeling with this code :
int ddd = myXml.getA().getCC().getDDD();
It is a strong violation of the law of Demeter. The class invoker have a too large knowledge of A, C and D. This code will be clearly difficult to adapt and maintain.
The two general approaches to this sort of problem are the null object pattern that other answers have already covered, and type safe nulls such as Scala's Option.
http://www.scala-lang.org/api/current/scala/Option.html
There are a few Java versions of Option knocking around.
http://functionaljava.googlecode.com/svn/artifacts/2.20/javadoc/fj/data/Option.html
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Optional.html
Type safe nulls can be particular useful when combined with the flatmap.
Use Apache common-beanutils to create your set method. It will use reflection and then you have only a single place to catch the errors.
It would look something like this (haven't coded it so excuse syntax errors).
int getInt(Object root, String beanPattern, int defaultValue)
{
try
{
return PropertyUtils.getNestedProperty(root, beanPattern);
}
catch (Exception e)
{
return 0;
}
}
This would be called like so.
int ddd = getInt(myXml, "A.CC.DDD", 0);
Can't you just write a function which is general enough to be called for each value, and is returning the value or 0.
Something like
myGetSomething(FOO){
try {getFOO} catch ...
}
Then your Code itself looks nice, but the function has basically a try-catch for each call.
Use Xpath query instead of get methods. It will give you an empty list if it cannot find the element path.
List ddds = myXml.query("/AA/BB/CC/DDD");
if (!ddds.empty()) {}
The correct syntax depends on the XML library you use.
Write part of the code in Groovy or Xtend; both support the ?. syntax which returns null of the left hand side of the expression evaluates to null. They also get rid of the useless get so you can write:
myXml.a?.cc?.ddd
The syntax of Xtend is worse when compared to Groovy but it compiles to plain Java, so you just need to add a single JAR with some helper classes to your code to use the result.