I have multiple pojo classes using below code.
public class ToStringImpl {
public String toString(){
StringBuilder result = new StringBuilder();
String newLine = "\n";
result.append( this.getClass().getName() );
result.append( " Data {" );
result.append(newLine);
//determine fields declared in this class only (no fields of superclass)
Field[] fields = this.getClass().getDeclaredFields();
//print field names paired with their values
for ( Field field : fields ) {
result.append(" ");
try {
result.append( field.getName() );
result.append(": ");
//requires access to private field:
result.append( field.get(this) );
} catch ( IllegalAccessException ex ) {
System.out.println(ex);
}
result.append(newLine);
}
result.append("}");
return result.toString();
}
}
How do I call above class from different classes?
Suppose I have pojo classes called customer, store, inventory
public class Customer {
private String name;
private String address;
...getter...setter...
public String toString(){
ToStringImpl log = new ToStringImpl();
//how do I pass different classes here?
return log.toString();
}
}
public class Store {
private String logo;
private String type;
....getter...setter...
}
public class Inventory {
private boolean isAvailable;
private long index;
...getter...setter
}
for each class how do I pass different class? or if there are better way to do this? or would it be better to create toString as interface and implement it in each class and pass it as constructor?
What you can do is make the toString() method in the ToStringImpl class static. I wouldn't call it toString() though, change it to something like getClassString()
Example:
public static String getClassString(Object o)
{
StringBuilder result = new StringBuilder();
String newLine = "\n";
result.append(o.getClass().getName());
result.append(" Data {");
result.append(newLine);
// determine fields declared in this class only (no fields of
// superclass)
Field[] fields = o.getClass().getDeclaredFields();
// print field names paired with their values
for (Field field : fields)
{
result.append(" ");
try
{
result.append(field.getName());
result.append(": ");
// requires access to private field:
result.append(field.get(o));
}
catch (IllegalAccessException ex)
{
System.out.println(ex);
}
result.append(newLine);
}
result.append("}");
return result.toString();
}
Then in your POJO classes, call it with:
public String toString()
{
// how do I pass different classes here?
// by passing the 'this' reference
return ToStringImpl.getClassString(this);
}
There is already a library that does this. Look up ToStringBuilder in the apache-commons library, your domain objects' toString method would look like:
#Override public String toString() {
return ToStringBuilder.reflectionToString(this);
}
The best plan would seem to me to be to rip out the homegrown code and drop in apache-commons, or use Project Lombok. If you must reinvent this wheel then copying ToStringBuilder's example of using a static method and taking the object to print as a parameter would be reasonable.
The ToStringBuilder includes a feature to let you restrict which fields get printed, your own code should do something similar for the sake of your own sanity. The toString method is used to print out information for debugging and logging. If you just get all the fields like your posted code it will dump out the entire object's contents every time you call toString in a log entry and you will have something that's unreadable, it will fill up your logs and slow down your application writing all this information.
You are the consumer of the information here, make it something that's useful instead of being overwhelming.
When you override a method, for example Object#toString(), you only override it for that class. You can do one of the following:
Add your toString() to every class that might need it and then just call toString() on that object from wherever it is. (not recommended)
extend your ToStringImpl on every class you want to and call toString() on object.
Make ToStringImpl#toString() static and pass an object as argument (recommended), for example:
public static void objectToString(Object ob){
//your code here, just replace "this" with "ob"
}
Related
I have a method getMyName and want to access the String myName outside the method.
public String getMyName() {
setTestStart("Returning name");
String myName = getActiveName().getMyName();
setTestInfo("My name is: " + myName);
setTestEnd();
return myName;
}
I want to get a String myName result and use that result in other methods without constantly calling the whole getMyName method. How can i do that? Sorry for this silly question, I am new in Java.
you could put your var out of the all method scopes
public class Test{
private String myName; // it's out of all scopes and will can catch in all methods
public void getMyName(){
setTestStart("Returning name");
myName = getActiveName().getMyName(); // setting value
}
public void testMyNameInOtherMethod(){
setTestInfo("My name is: " + myName); // reading value. so important treating non-declaring and null values
setTestEnd();
}
// others methods...
}
you can use contructors to set values when init instances of new class as well
I am extracting concept from a single page and that page is being used in different functions, so i have created a function that assigns the value if value hasn't been assigned yet.
public String text() {
if (text.isPresent()) {
return text.get();
}
this.text = Optional.of(extractText(pdDocument));
return text.get();
}
I would like to create a test that checks that the function is being called once and the context is shared between the functions that doing some functionality in the same context
Here is an example when text() is being called twice
private Optional<String> packingListNet() {
return locatePattern(text(), PACKING_LIST_NET);
}
private Optional<String> packingListNumber() {
return locatePattern(text(), PACKING_LIST_NUMBER);
}
Would be grateful for any information, thank you
The technical answer: you could use a mocking library, such as PowerMockito, to create mocked instances of the Optional class. And when you have a mock object, you can instruct the mock how to react to method calls. Then you need to "get" the mocked Optional object into your class under test.
You could use that to cover the first if statement: you expect the mock to see the isPresent() call, to return true, and to then return a specific string. Your testcase could then check "that expected string came back". Similar for the other way round, when the mocked Optional "is empty", then you ensure another string is returned, and you check for that.
But honestly, it is doubtful if you should do that all.
You should focus on the public contract that your method there provides.
And that would mean:
Enable yourself that you can pass in a (real) Optional object into the class under test
When your Optional is not empty, your test expects ... what you put into it
When your Optional is empty, your test expects whatever extractText() will return
Of course, mocking is really problematic here: Optional is a final class. So you need to either use Mockito with "experimental support for final enabled", or you need to use PowerMock(ito) (which I strongly advise to never use).
So, as said: avoid mocking.
I think this method is badly conceived. It may rely on private, mutable state that will be a problem with multiple documents and threads accessing them.
A better approach would be to pass all the necessary information as method parameters. They are thread safe that way;
public static String getText(String textToSearchFor, Document pdfDocument) {
// extract here
}
Here's how I might write a JUnit test for a method like this:
public class TextMethodOwnerTest {
#Test
public void testGetText_Success() {
// setup
String expected = "text to find";
Document pdf; // Have to get this.
// exercise
String actual = TextMethodOwner.getText(expected, pdf);
// assert
Assert.assertEquals(expected, actual);
}
#Test
public void testGetText_PackingListNumber() {
// Add another case here
}
#Test
public void testGetText_PackingListNet() {
// Add another case here
}
}
I am not sure what are you trying to ask. Information is not clear but maybe this can help you:
Junit and mockito are mostly used togther. If you want to check any function gets called only one time we use verify() method of mockito with parameter atLeast(1)
For example: Example taken from (https://www.baeldung.com/mockito-verify)
List<String> mockedList = mock(MyList.class);
mockedList.clear();
mockedList.clear();
mockedList.clear();
verify(mockedList, atLeast(1)).clear();
Here is some pseudo code how you could achieve it:
public Class {
int counter = 0;
void test() {
counter++;
}
}
public ClassTest {
public Class class;
void shouldBeCalledOneTime() {
class.test();
AssertThat(class).hasFieldWithValue("counter", 1);
}
}
Since your question seemed to me mostly about reading the file only once, which is quite a genuine need for many, I wrote up this class using your code, but without JUnit.
This has a main method that calls the packingList*() method 100 times to different threads, but you will see that the extraction part is entered into only once in the beginning. For this, I have added a lock and used a synchronized block. I understand that this is basic, but thought I may share since it might help others.
Note the changes in the method public String text().
public class ReusedText{
private static final long PACKING_LIST_NET = 200;
private static final long PACKING_LIST_NUMBER = 120;
private Optional<String> text = Optional.ofNullable( null );
private Document pdDocument;
private static final Object LOCK = new Object();
private static final ExecutorService svc = Executors.newFixedThreadPool( 2 );
public ReusedText(Document pdDocument) {
super();
this.pdDocument = pdDocument;
}
public static void main( String[] args ){
ReusedText rt = new ReusedText( new Document( "/path/to/document/on/disk" ) );
for( int i = 0; i < 100; i++ ) {
svc.submit( () -> System.out.println( rt.packingListNet() ) );
svc.submit( () -> System.out.println( rt.packingListNumber() ) );
}
svc.shutdown();
}
public String text() {
if (text.isPresent()) {
return text.get();
}
else {
synchronized (LOCK) {
/* This repeated 'if' block is necessary because 'text' may have got populated while this thread was waiting for lock. */
if (text.isPresent()) return text.get();
else{
System.out.println( "Extracting text..." );
this.text = Optional.of( extractText( pdDocument ) );
return text.get();
}
}
}
}
private String extractText( Document doc ) {
//Read the file contents using some API like java.nio.file.Files or Apache Tika
return "file contents here!";
}
private Optional<String> packingListNet() {
return locatePattern(text(), PACKING_LIST_NET);
}
private Optional<String> packingListNumber() {
return locatePattern(text(), PACKING_LIST_NUMBER);
}
private Optional<String> locatePattern( String text, long packingListNumber ){
//Implement your logic with the text here.
return Optional.of( String.valueOf( packingListNumber ) );
}
private static class Document{
private String pathToText;
public Document(String pathToText) {
super();
this.pathToText = pathToText;
}
public String getPathToText(){
return pathToText;
}
}
}
I am extending the class ClassVisitor and overriding the method visitMethod. Then I extend the MethodVisitor and override the visitMethodInsn. When I override the visitMethod I create a new instance of the extended MethodVisitor.
Please see the code below to understand. Keep in mind knowledge of the ASM library is required in order to understand it properly.
GraphClass.java:
public class GraphClass extends ClassVisitor {
public GraphClass() {
super(ASM5);
}
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
System.out.println("testing " + name + desc);
GraphMethod newVisitor = new GraphMethod();
return newVisitor;
}
}
GraphMethod.java:
public class GraphMethod extends MethodVisitor{
public GraphMethod() {
super(ASM5);
}
public void visitMethodInsn(int opcode, java.lang.String owner, java.lang.String name, java.lang.String descriptor, boolean isInterface) {
System.out.println(owner + name);
}
}
What I am trying to do is pass the name variable from visitMethod to be printed along with the other variables in the visitMethodInsn.
I am new to Java, so any tips would be very helpful.
Based on the comments I will assume that you want to know which methods call by methods of the visited class, all right?
It takes solved easy by using tree-api of objectweb asm.
ClassReader cr = new ClassReader(bytesOfSomeClass);
//Used class node instead of visiter
ClasaNode cn = new ClassNode(<asm version>);
cr.accept(cn, 0);
//Iterate all methods of class
cn.methods.forEach( (MethodNode mn) -> {
String callerName = mn.name;
//Iterate all instructions of current method
Stream.iterate(mn.instructions.getFirst(), AbstractInsnNode::getNext).limit(instructions.size())
.filter(node -> node instanceof MethodInsnNode) //take only method calls
.forEach(node -> {
String calledName = ((MethodInsnNode) node).name;
//Print results
System.out.println(calledName + " is called by " + callerName);
});
});
This is probably a bad question, but i have constructed a DVD object in java:
DVD myDVD = new DVD (11.17 , 9 , 120 , " Howl ’s Moving Castle " , " Hayao Miyazaki " );
I have a toString to print the whole object, but I've been asked to print the director (Hayao Miyazaki) of the object without the rest, is there a way to do this?
If you need any more information in order to help, please comment. Thanks
create a get method for the director
public String getDirector(){
return director;
}
System.out.print(myDVD.getDirector());
Assuming your code is Java code, in your DVD class, you can override the toString method in order to print what you want:
public class DVD {
private String director;
//more fields and stuff
#Override
public String toString() {
return director;
}
}
If you already have a toString implementation and need another one, you can add another method to get the director:
public String getDirector(){
return director;
}
and print it:
System.out.print(myDVD.getDirector());
Or you may want a method to do the printing itself:
public void printDirector() {
System.out.println(director);
}
You could make it as simple as writing a new method printDirector() which would do just that, OR...
You could leave the responsibility of printing the information to some other class, and make the DVD object responsible only for providing its information:
public class Movies {
public class DVD {
private director;
public DVD(String director) {
this.director = director;
}
public String getDirector() {
return director;
}
}
public static void main(String... arg) {
DVD howl = new DVD("Miyazaki");
String director = howl.getDirector();
SomePrinterClass.print(director);
}
}
Ultimately that's a design decision, either will produce the same result.
I have a class X with maybe 100 String in it and I want to do a function that mock an object of this class for all the setters which begins by "setTop".
For the moment I did this :
public void setFtoMethods(Class aClass){
Methods[] methods = aClass.getMethods();
for(Method method : methods){
if(method.getName().startsWith("setTop")){
method.invoke ....
}
}
}
And I don't know how to do now and I'm not pretty sure I can fill all these setters like that. In my environment I can't use frameworks and I'm in Java 6.
You CANNOT fill the setters because they are methods (functionallities), not values itselfs. But...
You CAN fill the value of the attributes (fields) of the class that corresponds to the getter.
Imagine you have a class:
class Example {
String name;
int topOne;
int topTwo;
int popTwo; // POP!!!
int topThree;
}
Taking:
this answer as model
your needs (getTopXXX will correspond to field topXXX)
You can get only needed fields with reflection in this way:
public static void main(String[] args) {
inspect(Example.class);
}
public static <T> void inspect(Class<T> klazz) {
Field[] fields = klazz.getDeclaredFields();
for (Field field : fields) {
if (field.getName().startsWith("top")) {
// get ONLY fields starting with top
System.out.printf("%s %s %s%n",
Modifier.toString(field.getModifiers()),
field.getType().getSimpleName(),
field.getName()
);
}
}
}
OUTPUT:
int topOne
int topTwo
int topThree
Now, do whatever you need inside the if (field.getName().startsWith("top")) { instead of a System.out.