SOLUTION
I was adding a new instance of A to the list: aList.add( new A() ), whose name property is of course null, instead of adding the actual initialized instance. Sorry for the dumb question.
I have this A class of ProjectA which overrides its toString method to return a clone of its name property, like this:
public class A {
private String name;
#Override
public String toString() {
return new String(name);
}
}
I then export this library to a jar and import it into ProjectB and when I call a.toString() I get a NullPointerException that says there is an error exactly on the return line: return new String(name);.
However, if I put it like this:
public class A {
private String name;
#Override
public String toString() {
return name;
}
}
I don't get any exception but the String returned is null.
I built the jar (ProjectA) using Eclipse and imported it into ADT (ProjectB - Eclipse too).
NOTE:
I omitted the getters/setters intentionally for the sake of simplicity, but they're in there in the original code and I'm pretty sure I set the name property way before calling the toString() method. In fact, if I call the getName() method, the name is returned perfectly fine, but I'm using lists and I need the toString() method.
This is the part of the code where the List of A objects is created (ProjectA too):
ArrayList<A> aList = new ArrayList<Categoria>();
for (int i = 0; i < random.nextInt(3)+1; i++) {
A a = new A();
a.setId(0);
a.setName("Test name");
a.setDescription("Test desc.");
aList.add(a);
Log.d("app", "Created object A: "+a.getName()); // The name is displayed OK here
}
aList.trimToSize();
And this is the exact part of the code where the toString() method is called (ProjectA):
new ArrayAdapter<A>(
actionBar.getThemedContext(),
android.R.layout.simple_list_item_1,
android.R.id.text1,
DataAccess.getAList() // The ArrayAdapter class calls the toString method to populate a list
)
As you could see, I in fact verify the content of the name property via the getName() method and it is okay. I have to mention that the first approach (the on which uses new String(name), without an finals nor null checks) worked flawlessly on another project.
This is the (relevant part of the) DataAccess class:
public final class DataAccess {
private static final Data data;
public static Arrayist<A> getAList() {
return this.data.getAList();
}
}
When you invoke new String(name); it invokes the overloaded parameterized constructor of String shown below :
public String(String original) {
int size = original.count;
........
.........
}
As you can see the first line in the code tries to compute the length of the String passed to the constructor. Since in your case the String is null invoking the member variable count on that null reference throws NullPointerException.
Note : In the code where you create AList, i dont see you adding the object to the list i.e. AList.add(a); is missing
return new String(name);
Would fail on name being null. It could happen on A a = new A(); System.out.println(a):.
The used constructor String(String) is a relict of the beginning of Java, reminiscent of the C++ copy constructor.
In Java String is immutable, and Java does not need the copy constructor.
Two solutions:
return String.valueOf(name); // Would return "null" for null.
return name == null ? "" : name;
As far as the exception goes you are getting a null pointer as already explained by #Kakarot.
This line blows up
original.count
But if you want to save yourself from null checking etc and at the same time have a efficient toString() method than user some thing like this.
public class A {
private String name = null;
private String address = " Some place";
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
return sb.append(name).append(address).toString();
}
}
Using string builder is efficient and you can see the output for the above toString() even with null values.
null Some place
In java new String(null) results into NullPointerException.
#Override
public String toString() {
if(name!=null){
return name;
}else{
return "";
}
}
Related
I have a method,
private String createSubjectColumnForOutgoing(Message message)
{
//TODO : Changes for blocking messages of spam users
if(message.getReceiverEnvelope() != null && message.getReceiverEnvelope().getUser() != null && message.getReceiverEnvelope().getUser().isBlocked())
{
return I18N.IN_REVIEW_BY_TEAM.msg();
}
return StringUtils.deSanitizeSpecialCharacters(message.getSubject());
}
and this method is called like this,
case OUTGOING:
table.addGeneratedColumn(I18N.MESSAGETABLE_HEADER_SUBJECT.msg(), this::createSubjectColumnForOutgoing);
break;
And the constructor in the class are,
public MessageTable(Directory directory, boolean withFilter, Device device)
{
this(directory, new FilterConfiguration(withFilter), device);
}
public MessageTable(Directory directory, FilterConfiguration filterConfiguration, Device device)
{
Objects.requireNonNull(directory);
Objects.requireNonNull(device);
this.directory = directory;
dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(LocaleAware.super.getLocale());
tableFooter = createTableFooter();
openButton = createOpenButton();
newButton = createNewButton();
messageTable = createTable(device);
tableFooter.addComponent(newButton, 0);
tableFooter.addComponent(openButton, 1);
final VerticalLayout layout = new VerticalLayout();
layout.addComponent(createFilterComponent(filterConfiguration));
layout.addComponents(tableFooter, messageTable);
layout.setComponentAlignment(tableFooter, Alignment.MIDDLE_LEFT);
rootLayout = layout;
setCompositionRoot(rootLayout);
}
When calling this method createSubjectColumnForOutgoing there is no parameter passed, and it is working perfectly. I am not able to understand from where data is coming in Message object. I googled but not able to understand it. Please help. Thanks in advance.
Code of addGeneratedColumn
public void addGeneratedColumn(Object id, Function<BEANTYPE, ?> generatedColumn)
{
String header = null;
if(id instanceof String)
{
header = (String) id;
}
addGeneratedColumn(header, id, (source, itemId, columnId) -> generatedColumn.apply(itemId));
}
this::createSubjectColumnForOutgoing is a method reference, not an execution of the createSubjectColumnForOutgoing method.
The table.addGeneratedColumn() method, to which you pass the method reference, may be calling the method of the functional interface implemented by this method reference. If it does, it passes a Message instance to it.
You haven't included the code of addGeneratedColumn(), so I don't know what type of functional interface it expects (perhaps a Function).
EDIT:
Following your edit, Function<BEANTYPE, ?> generatedColumn is the functional interface implemented by the method reference you pass to addGeneratedColumn(). This means that generatedColumn.apply(itemId) is the statement that executes the createSubjectColumnForOutgoing() method, and you can see that itemId is passed to the method. This means that itemId must be a Message instance.
Note that addGeneratedColumn(Object id, Function<BEANTYPE, ?> generatedColumn) doesn't execute the createSubjectColumnForOutgoing() method either. It passes a functional interface (implemented by a lambda expression) that can execute that method to a second addGeneratedColumn method.
This is a general issue/problem that I have come across. I wondered if anyone knows of any well suited design patterns or techniques.
private ExternalObject personObject;
private String name;
private int age;
private String address;
private String postCode;
public MyBuilderClass(ExternalObject obj)
this.personObject=obj;
build();
}
public build() {
setName(personObject.getName());
setAge(personObject.getAge());
setAddress(personObject.getAddress());
setPostCode(personObject.getPostCode());
.
.
. many more setters
}
The class above takes external objects from a queue and constructs MyBuilderClass objects.
A MyBuilderClass object is successfully built if all of the fields have been set to non-null non-empty values.
There will be many MyBuilderClass objects that cannot be built because data will be missing from the ExternalObject.
My problem, what is the best way to detect if an object has been correctly built?
I could check for null or empty values in the set methods and throw an exception. The problem with this approach is throwing exceptions is expensive and it will clogg the log files up because there will be many instances where an object cannot be built;
What other approaches could I use?
Correct me if I'm wrong: you are trying to find a good way to check if an object is valid, and if it is not, tell the client code about this without using an exception.
You can try a factory method:
private MyBuilderClass(ExternalObject obj)
this.personObject=obj;
build();
}
public static MyBuilderClass initWithExternalObject(ExternalObject obj) {
// check obj's properties...
if (obj.getSomeProperty() == null && ...) {
// invalid external object, so return null
return null;
} else {
// valid
MyBuilderClass builder = new MyBuilderClass(obj);
return builder.build();
}
}
Now you know whether an object is valid without using an exception. You just need to check whether the value returned by initWithExternalObject is null.
I wouldn't throw exceptions in cases that aren't exceptional. And as the only way for a constructor not to produce an object is to throw, you should not delay validation to the constructor.
I'd still recommend the constructor to throw if its results were to be invalid, but there should be a validation before that, so you don't even call the constructor with an invalid ExternalObject.
It's up to you if you want to implement that as a static method boolean MyBuilderClass.validate(ExternalObject) or by using the builder pattern with this validation.
Another approach for such a validation is to use java Annotations:
Make a simple annotaion class, let's say Validate:
#Target({ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
#interface Validate {
boolean required() default true;
}
then annotate the fields you want to be present as #Validate(required=true):
class MyBuilderClass {
private ExternalObject externalObject;
#Validate(required=true)
private String name;
#Validate(required=false) /*since it's a primitive field*/
private int age;
#Validate(required=true)
private String address;
#Validate(required=true)
private String postCode;
MyBuilderClass(ExternalObject externalObject) {
this.externalObject = externalObject;
build();
}
public void build() {
setName(personObject.getName());
setAge(personObject.getAge());
setAddress(personObject.getAddress());
setPostCode(personObject.getPostCode());
}
//.
//.
//. many more setters
}
And then add this method in the MyBuilderClass class, in order to check if your Object is built correctly:
public boolean isCorrectlyBuilt() throws IllegalAccessException {
boolean retVal = true;
for (Field f : getClass().getDeclaredFields()) {
f.setAccessible(true);
boolean isToBeChecked = f.isAnnotationPresent(Validate.class);
if (isToBeChecked) {
Validate validate = f.getAnnotation(Validate.class);
if (validate.required()/*==true*/) {
if (f.get(this) == null) {
retVal = false;
break;
/* return false; */
}
}
}
}
return retVal;
}
Here is an example of use :
public static void main(String[] args) throws Exception {
ExternalObject personObject = new ExternalObject();
personObject.setAge(20);
personObject.setName("Musta");
personObject.setAddress("Home");
personObject.setPostCode("123445678");
MyBuilderClass myBuilderClass = new MyBuilderClass(personObject);
System.out.println(myBuilderClass.isCorrectlyBuilt());
}
Output : true because the object is correctly built.
This will allow you to choose the fields that you want to be in the structure by reflection, without bringing those inherited from a base class.
As this previous answer suggests, here are 2 options either of which should be added after you have tried to set the variables.
use reflection to check whether any of the variables are null. (As mentioned in comments this will check all fields in this object but be careful with fields in any superclasses).
public boolean checkNull() throws IllegalAccessException {
for (Field f : getClass().getDeclaredFields())
if (f.get(this) != null)
return false;
return true;
}
perform a null check on each variable.
boolean isValidObject = !Stream.of(name, age, ...).anyMatch(Objects::isNull);
Previous answer
From what I've come across you could overwrite the equals method of your object and compare it with a valid example object. Its dirty and might only work in some cases.
Your approach is the best I could think of. Write a seperate method or class that has for example a static validate method. You could reuse it anywhere.
I am new to Java and I have failed to find anything about this case.
I am basically trying to pass this array called vakken to a new class called Vak,
Vak expects to receive a String and a int.
Vak[] vakken = new Vak[1];
vakken[0] = new Vak("Test",3);
Vak vak = new Vak(vakken[0]);
Whenever I try the code above I get this error.
Exception in thread "main" java.lang.UnsupportedOperationException: Not supported yet.
at ectsmonitor2.Vak.<init>(Vak.java:24)
at ectsmonitor2.ECTSmonitor2.main(ECTSmonitor2.java:27)
Java Result: 1
Vak.class
public class Vak {
public String naam;
public int teVerdienenEcts;
public Vak(String vakNaam, int vakTeVerdienenEcts){
naam = vakNaam;
teVerdienenEcts = vakTeVerdienenEcts;
}
}
You haven't actually coded your constructor that takes a Vak yet, you made it throw UnsupportedOperationException. Put some code in the constructor e.g.
public Vak(Vak v) {
this(v.naam, v.teVerdienenEcts);
}
This line wont work for sure
Vak vak = new Vak(vakken[0]);//IDE will display error message here
Because you have no such constructor for this.
Create a new constructor that takes an object of its own type.
Similar to this:
public Vak(Vak anObject){
//do stuffs here
}
These type of constructors are called copy constructors
And generally you won't want your attributes to be public. Make them private.
I want to do something like this:
Creator method = new Creator();
method.addSubject("example");
class Creator{
public void addSubject(String subjName) {
//here is the issue
subjName = new Subject(subjName);
}
}
class Subject {
private String name;
public Subject(String newName) {
name = newName;
}
}
So I want this class called Creator to be able to make Subjects, but I need it to be able to do so by passing it a String with the name that I want to call those subjects. How can I do this?
Edit: To clarify, the class "Creator" has a method called "addSubject". In the main method of the program I have an object of Creator called "method" (probably should have chosen a better example name). So can this object of Creator make objects of another class, class "Subject", simply by passing the method "addSubject" the name I want those objects of Subject to have?
Edit2: This is the pseudocode of what I want:
Main method:
Initialize Creator object
Command line for program takes arguments
Pass these arguments to creator object
Creator Object:
Takes command line argument in the form of string and makes a new object of the class Subject by the name of the String
I think you want to create a new object of a class that you just want to use the name. Is it? So, you can do this (Java 7).
try {
// you need to provide the default constructor!
Object newInstance = Class.forName( "your.package.YourClassName" ).newInstance();
} catch ( ClassNotFoundException | IllegalAccessException | InstantiationException exc ) {
exc.printStackTrace();
}
If you are using a Java version prior to 7, you need to use 3 catch statements, one for ClassNotFoundException, one for IllegalAccessException and one for InstantiationException.
Edit: I think I understood now. You want to create instances of Subject with a name passed to the method. You can use a HashMap to simulate this.
Something like:
import java.util.*;
class Creator{
private Map<String, Subject> map = new HashMap<String, Subject>();
public void addSubject(String subjName) {
map.put( subjName, new Subject(subjName) );
}
public Subject getSubject(String subjName) {
return map.get(subjName);
}
}
class Subject {
private String name;
public Subject(String newName) {
name = newName;
}
#Override
public String toString() {
return name;
}
}
// using...
Creator method = new Creator();
method.addSubject("example");
// prints example
System.out.println( method.getSubject("example") );
// prints null, since there is not a value associeted to the "foo"
// key in the map. the map key is your "instance name".
System.out.println( method.getSubject("foo") );
This is the bit that doesn't work:
subjName = new Subject(subjName);
subjName is a string, but of course a new Subject() is a Subject
How about
Subject myNewSubject = new Subject(subjName);
Of course, I imagine what you really want is to deliver that Subject somewhere (to a Collection maybe?) but your question doesn't clarify so I'll leave it at that.
I have the following Class
public class Booking{
public String name;
public String comment;
public String session;
public void test(){
this.name = "hi";
}
}
I instrument it using the following:
cc.instrument(new ExprEditor(){
public void edit(FieldAccess arg) throws CannotCompileException {
if (arg.isWriter()) {
StringBuffer code = new StringBuffer();
code.append("$0.");
code.append(arg.getFieldName());
code.append("=$1.toUpperCase();");
arg.replace(code.toString());
}
}
});
Now when I call this:
Booking b = new Booking();
b.name = "hello";
System.out.println(b.name); // Edited correction
b.test();
System.out.println(b.name);
Gives me
hello // Externally, doesn't.
HI // Internally, works as expected
What am I missing? It just seems like one of those things I should be able to accomplish easily.
Please don't tell me I have to do a blanket "fieldAccess.replace" on all classes? O.O
Your example code fragment that contains the statement b.name = "hello"; isn't being instrumented, hence the value it writes is not converted to uppercase. An ExprEditor can only transform the field access from classes that are instrumented by it. If you want every write to the 'name' field converted to uppercase, you will have to instrument every class that contains a write statement for that field.