Convert instanced object to string - java

I initialize a Password object and I am having trouble using the same object as a string for later purposes like counting the amount of letters in the string. I know that I'm only getting the textual representation of the object with the methods String.valueOf and .toString. How do I go about taking the my object pass and getting the "hello" string I initialized it with?
public class Password {
public Password (String text) {
}
public String getText(){
String string = String.valueOf(this);
return string;
}
public static void main (String[] args) {
Password pass = new Password ("hello");
System.out.println(pass.toString());
}
}

Your actual getText() method doesn't make sense :
public String getText(){
String string = String.valueOf(this);
return string;
}
You try to recreate a String from the toString() method of the Password instance.
It is really not necessary (useless computation) and it is clumsy as toString() is not designed to provide a functional data.
To reach your goal, it is very basic.
Store the text in a field of the Password instance :
public Password (String text) {
this.text = text;
}
And provide a view on the text field.
You could replace getText() in this way :
public String getText(){
return text;
}

Use fields.
public class Password {
private String text; // This is a member (field) It belongs to each
// Password instance you create.
public Password(String value) {
this.text = value; // Copy the reference to the text to the field
// 'text'
}
}
The problem with String.valueOf(this), where this is a Password instance, is that the valueOf() method has absolutely no idea of how to convert a Password instance to a field. You named it "Password", but it could also beMyTextorMySecret. So you need to tell how aPasswordinstance can be displayed as text. In your case, you'll need to just use thetext` field from the abovementioned example.
You should definitely read the docs about classes. I think you're missing something basic.
Note: You should also never store a password into a String, because of security implications, but that's a whole other story, and beyond the scope of your question.

Related

What to do with a class where one particular variable is sometimes not used

Beginner question here. I'm writing a Java program that queries a public API on the internet to retrieve details of discussions on a forum. The data comes back as JSON and I'm parsing that into Java objects to be used in my program.
A discussion normally contains five attributes, i.e. the five public variables. However, in response to a limited number of specific search types, the number of comments is not returned.
Is there a 'best' (in terms of object oriented programming) way to deal with this sort of scenario? My first attempt is below, where I have simply written two constructors, one that assigns a value to numberOfComments, and one that does not.
This doesn't seem like a great solution - what happens if another class creates a DiscussionDetails object, uses the constructor that does not populate numberOfComments, but then later tries to use the numberOfComments field?
I thought that maybe it should be split into two classes, where DiscussionDetails has no numberOfComments field, and DiscussionDetailsSpecialised is a subclass with an additional numberOfComments field. This feels a bit like overkill to me, for the sake of one single field.
Or maybe there's a convention that such a variable is initialised with a particular value like 'false' or '-1' or something?
Are there other, better approaches that an experienced programmer would use for this kind of situation?
I know the example is trivial, but I'm using it to try to illustrate my question as simply as possible.
/**
* Wrapper for a set of JSON data returned from an API
*/
public class DiscussionDetails
{
public String discussionID;
public String discussionName;
public String discussionURL;
public String submittedDate;
public String numberOfComments;
/**
* Constructor that populates all fields
*/
public DiscussionDetails(String discussionID, String discussionName, String discussionURL, String submittedDate, String numberOfComments)
{
this.discussionID = discussionID;
this.discussionName = discussionName;
this.discussionURL = discussionURL;
this.submittedDate = submittedDate;
this.numberOfComments = numberOfComments;
}
/**
* Constructor method to use when the number of comments is unknown, which happens in certain specific cases
*/
public DiscussionDetails(String discussionID, String discussionName, String discussionURL, String submittedDate)
{
this.discussionID = discussionID;
this.discussionName = discussionName;
this.discussionURL = discussionURL;
this.submittedDate = submittedDate;
}
}
This has been traditionally solved with "special" values (values that obviously make no sense, eg: -1 for a count) or null (which in a sense is the most special value).
The "best" way to deal with this is, IMHO, java.util.Optional: clients have to check if a value is present when they wish to use it and Optional makes this explicit, avoiding the common source of bugs of a client forgetting to check.
One way to solve this is with a builder. Your example is good, but a builder can help make it more obvious what's going on.
/**
* Wrapper for a set of JSON data returned from an API
*/
public class DiscussionDetails
{
public String discussionID;
public String discussionName;
public String discussionURL;
public String submittedDate;
public String numberOfComments;
public static class Builder{
private DiscussionDetails dd = new DiscussionDetails();
public discussionID(String discussionID) {
dd.discussionID = discussionID;
return this;
}
public discussionName(String discussionName) {
dd.discussionName= discussionName;
return this;
}
public discussionURL(String discussionURL) {
dd.discussionURL= discussionURL;
return this;
}
public submittedDate(String submittedDate) {
dd.submittedDate= submittedDate;
return this;
}
public numberOfComments(String numberOfComments) {
dd.numberOfComments= numberOfComments;
return this;
}
public DiscussionDetails build() {
return dd;
}
}
}
This can make your instantiation a little cleaner, especially with optional fields or a lot of fields.
You would use this like:
DiscussionDetails details =
new DiscussionDetails.Builder()
.discussionID("1")
.discussionName("Name")
.build();
In this particular case, I've set 2 of the fields. The other fields would be null, or the default value. With some extra code, this gives you a lot of flexibility and arguably makes the code easier to read.
If you need to enforce certain fields being set, you can add more methods in the Builder class itself, or throw an error from the build method.
The "special" value for handling a case when there is no value for a given property is a null value (nil in some languages). However, you should document this in your code so that the client of the code knows that the numberOfComments can be null - forgetting about it and trying to use the value ends with one of the most common exceptions - NullPointerException.
call this in your constructor
public class DiscussionDetails {
public String discussionID;
public String discussionName;
public String discussionURL;
public String submittedDate;
public String numberOfComments;
/**
* Constructor that populates all fields
*/
public DiscussionDetails(String discussionID, String discussionName, String discussionURL,
String submittedDate, String numberOfComments) {
this(discussionID, discussionName, discussionURL, submittedDate);
this.numberOfComments = numberOfComments;
}
/**
* Constructor method to use when the number of comments is unknown, which happens in certain
* specific cases
*/
public DiscussionDetails(String discussionID, String discussionName, String discussionURL,
String submittedDate) {
this.discussionID = discussionID;
this.discussionName = discussionName;
this.discussionURL = discussionURL;
this.submittedDate = submittedDate;
}
}

getting strings from other classes

hi guys im writing a method that contains a string name from other classes..
i use the String apkName and mcurrentPhotoPath in alot of activites but need to pass the value of them string into my download method.
ive tried this
public static class Stringz{
public String APK() {
return apkNames;
}
public String FILEPATH() {
return mCurrentPhotoPath;
}
}
then in my download method i use
Stringz st = new Stringz();
String apkNames = st.APK();
String mCurrentPhotoPath = st.FILEPATH();
which works fine for a single activity. but because i have multiple activites using the same string names how can i write it so my method know which string to look for in every activity
thanks guys
You need one of these two:
1) An instance of Stringz
2) A static reference to the Strings you want to access
A static reference you define as:
public static String yourString = "Some string";
And instance:
public Stringz reference = new Stringz();
//and access like:
reference.yourString;

bindFromRequest validation null

I am new to the Java Play Framework and I'm trying to get the authentication to work. So I am following this tutorial: https://www.playframework.com/documentation/2.1.0/JavaGuide4
Here is my code:
public static Result authenticate()
{
Form<Login> loginForm = form(Login.class).bindFromRequest();
return ok(loginForm.toString());
}
public static class Login
{
public String email;
public String password;
public String validate()
{
return "VALIDATE "+email+password;
}
}
In the method autheticate() I can see the submitted values of the form, but the method validate() in the Login class does not see them (the variables are always null).. The output of loginForm.toString() contains:
Form(of=class controllers.Application$Login, data={email=asdf#asdf, password=asdf}, value=None, errors={=[ValidationError(,[VALIDATE nullnull],[])]})
As you can see, the data is received.. But in the validate method the data suddenly is equal to null. So how do I fix this?
You don't mention how you are calling validate() however I think this might do the trick, do something along the lines of:
public static Result authenticate() {
Form<Login> form = form(Login.class).bindFromRequest();
// handle errors
if (!form.hasErrors()) {
Login login = form.get();
Logger.debug(login.validate());
} else {
// bad request
}
}
This works for me.
Method validate in your model should return null if you think that validation has passed, otherwise you should return error message text. Then you need to check form if it contains error by "hasGlobalError" method. globalError is filled when validate() method returns String instead of null. But in your case you should use some model field annotations - https://www.playframework.com/documentation/2.3.x/api/java/play/data/validation/Constraints.html.
If you want to check if form fails on those - then you use "hasErrors" method.
public static class Login {
#Constraints.Email
public String email;
#Constraints.MinLength(value = 6)
public String password;
}
Such model will check if provided emails is really email and if password is longer or equal 6 characters.
ps. Do not use toString on template, you should use render()

How to handle password Strings in ADF Faces?

Per company policy (and other recommendations), we should not use String class to handle passwords. Because this objects are immutable and may live until the GC deallocates it, so a "memory inspection" could show a not yet deallocated String containing the password. So the alternative is to use char[] instead and overwrite it contents once is no longer needed. However, when using an
inputText component, the setter method must receive a String.
I have an inputText like:
<af:inputText value="{myBean.password}" secret="true"/>
And
public class MyBean {
...
private transient char[] password;
...
public void setPassword(String password) {
this.password = password.toCharArray();
}
...
public void sumbit(ActionEvent e) {
...
//Wipe password
for(int i = 0 ; i < password.length ; i++) { password[i] = ' '; }
password = null;
}
}
As you can see, there is still a String object containing the password (the argument of the setter), and I don't know how to deal with that value. Is there any way to receive a char[] value? Does the cycle of ADF contemplates the fact that this is a password and should do something special?
This is a server and calling the CG is not a good idea.
One way I could think is passing the value of the password field from client to server in an encrypted format using JavaScript encryption libraries and decrypt it on the server. This way the receiving string will be in a non plain text format.
Instead of keeping the value of the component in the bean, keep a reference to the component itself:
<af:inputText bindings="{myBean.password}" secret="true"/>
......
private RichInputText password;
......
public void setPassword(RichInputText password) {
this.password = password;
}
public RichInputText getPassword() {
return password;
}
and in action listener get the value from the component:
public void sumbit(ActionEvent e) {
char[] pswd = password.getValue().toCharArray();
............
}
Hope this helps.

Javassist - redirect field access to methods (doesn't work)

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.

Categories