Looking through the Play documentation for Java I noticed the following block of code:
public static Result show(Long id) {
Client client = Client.findById(id);
return ok(views.html.Client.show(client));
}
Source: http://www.playframework.com/documentation/2.1.0/JavaRouting
I am having some trouble understanding the second line, my understanding of Java Object creation is a typical constructor looks like the following:
Person john = new Person();
What is the second line doing? Creating a Object called client from Class called Client, also what is Client? It doesn't appear to be a part of the Play Framework, certainly I cannot find anything in JavaDocs.
Thanks
Edit:
I found this to be a good point of reference for the answer (http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html)
Also I think the class Client comes from the following documentation (http://www.playframework.com/documentation/1.1.1/controllers) with Client being just a example model class, the new documentation probably needs updating to clear up this confusion.
Pretty clearly, the class Client has a static function of findById, which takes a Long and returns a Client. Static functions are functions that are defined without any access to object properties, and therefore can be accessed through the class name, rather than having to be accessed through an object. Most likely, the class has a static property containing a collection of all clients in the system by index, and findById grabs an existing Client from that list.
I really have no idea where the class Client is defined, however. I've also made a quick look around for it, and couldn't find it in the obvious places.
There must be a static method called show(Client) on the views.html.Client class that returns some object. That object is passed into an ok(whatever) method, and that ok method returns a Result object.
You're missing some basic knowledge/experience. The sample you gave has nothing to do with routes and in this snippet only first line is important, second is just some hypothetical usage. De facto it could be just...
public static Result show(Long id) {
return ok("You want to display details of client with ID: " + id);
}
Although #BenBarden explained what is that mean correctly , this static method isn't declared anywhere, it's (again) hyphotetical usage of some ORM. For an example the real usage with Ebean's model will be:
Client = Client.find.byId(id);
Of course you can also declare own method in your Client model and name it the same as in the sample, however it will be just only wrapper:
public static Finder<Long, Client> find
= new Finder<>(Long.class, Client.class);
public Client findById(Long id) {
return find.byId(id);
}
Conclusions
You need to examine some samples available with your Play sources to get familiar with some basic syntax, fortunately you'll find it easy.
DO NOT MIX documentation from Play 1.x with Play 2.x they are not compatible!
Related
I'm very new to programming language. My question might not even make sense. My environment is using java and trying to implement both ios and android apps in the same automation testing framework.
So, the idea is that any test script should be able to run on both the apps. Ex: one signin test script should be run for both ios and android.
I've decided to use interface and class implementation approach. The problem I'm facing is with test data. My company doesn't want to use excel. They want to use json for test data.
Here's my problem, look at the following line of code:
ValidBuy goodBuy = JsonFileReader.loadDaTa(TestBase.DATA_PATH, "good-buy.json", ValidBuy.class);
As you can see I have a class "ValidBuy" that has all the getters for a particular json file. I have another class "JsonFileReader" which takes the json filePath, fileName, and a class as an input and returns the data for that class name that I passed in. For this example I've passed ValidBuy.class
So, when I run a positive test, I'm passing "goodBuy" variable which is of type "ValidBuy". The problem starts here.
The test case is now specified with the data from goodBuy because it's type is "ValidBuy" and I'm passing goodBuy as a parameter.
Look at one of my extracted methods:
private void enterBuyInfo(ValidBuy goodBuy) {
itemPage = nativeApp.getItemPage(goodBuy);
itemPage.setItemName(goodBuy.getItemName());
itemPage.setItemSize(goodBuy.getItemSize());
itemPage.setItemDigitSSN(goodBuy.getSsn());
itemPage.clickContinue();
}
You can see those getters I'm using are coming from ValidBuy class.
If I run this test with the data for a badBuy:
InvalidBuy badBuy = JsonFileReader.loadDaTa(TestBase.DATA_PATH, "bad-buy.json", InvalidBuy.class);
It fails because now I have to change "ValidBuy" class with "InvalidBuy" class. Since, changing the parameter in the extracted method in every run is not possible, how can I make it more generic?
I want something like this:
TestData data = JsonFileReader.loadDaTa(RESOURCES_PATH, "good-client.json", InvalidBuy.class);
Here, TestData is generic. It could either be a class or interface (I don't know if that's possible) and the return type will be specified by whichever class I pass into the loadData() method. In this case InvalidBuy.class
The extracted method should look like this:
private void enterBuyInfo(TestData data) {
itemPage = nativeApp.getItemPage(data);
itemPage.setItemName(data.getItemName());
itemPage.setItemSize(data.getItemSize());
itemPage.setItemDigitSSN(data.getSsn());
itemPage.clickContinue();
}
If I can do this, I can use those extracted methods to create more tests.
I know I wrote a lot. I've only tried to make it as clear as possible. If it doesn't make any sense, just disregard it.
Any suggestions, ideas, code samples will be highly appreciated.
Firstly let me see if I understand your question. I think you are saying that loadData may return a value of type ValidBuy or InvalidBuy and you want to pass into it the class that you want returned. You then want to know how to use an interface that might represent either of these classes in your test methods so you can test various return values (both valid and invalid). You use the term "generic" in your question but I'm guessing you don't mean to use it in the specific way it's used in Java.
If I've understood your question correctly, then here's an answer:
Passing the class you wish to have returned into a method is an unusual usage and almost certainly not ideal. Better OOD would be to extract the common methods for all objects returned from loadData into an interface.
So:
interface Buy {
String getItemName();
boolean isValid();
}
class ValidBuy implements Buy {
#Override
public boolean isValid() {
return true;
}
...
}
class InvalidBuy implements Buy {
#Override
public boolean isValid() {
return false;
}
...
}
class JsonFileReader {
Buy loadData(Path path) {
...
}
}
Then your tests can look like:
#Test
void testValidBuy() {
assertTrue(reader.loadData(validPath).isvalid());
}
#Test
void testInvalidBuy() {
assertFalse(reader.loadData(invalidPath).isValid());
}
I realise I've simplified it a bit but hopefully you get the idea.
Using MongoDB, I need to persist objects from Twitter4J. Twitter4J uses interfaces, which are implemented in JSON versions. Example:
The API returns Status (an interface), and Status is implemented as StatusJSONImpl.
I can't save Status to MongoDB, I need to implement StatusJSONImpl.
My issue is, this class StatusJSONImpl is not public (see here) so I can't use it in my code. I tried to download the source of Twitter4J to manually add "public" to StatusJSONImpl: I can do:
Status status = twitter.updateStatus(latestStatus);
String statusStringified = TwitterObjectFactory.getRawJSON(status);
StatusJSONImpl statusImplemented = (StatusJSONImpl) TwitterObjectFactory.createUserList(statusStringified);
SingletonLaunchDB.getMongo().save(statusImplemented);
But I still get a java.lang.IllegalAccessError on the class StatusJSONImpl at run time.
I see from other SA answers that users routinely point other users to this Impl classes... how do they do to use it in their code?
Your help is much appreciated.
Status is serializable. To recover StatusJSONImpl from statusStringified you can write.
JSONObject json = new JSONObject(statusStringified);
Status status = new StatusJSONImpl(json);
The code sample is from StatusSerializationTest.java
I hope this helps.
Use the static factory method on TwitterObjectFactory:
Status status = TwitterObjectFactory.createStatus(statusAsString);
StatusJSONImpl is an implementation detail which library users are not meant deal with. The only thing a user of the library should care about is the contract (the Status interface in this case) which is necessarily public and the library authors promise to fulfill. On the other hand, the concrete classes like StatusJSONImpl are not public on purpose in order to prevent consumers from using them and getting tightly coupled to a specific implementation which may change over time. And from the authors' point of view, by coding to an interface they are then free to return any concrete type they wish as long as it fulfills the contract.
If you check the class that is returned from the factory method, it is StatusJSONImpl. But to reiterate, as a user of the library you should need to know or care about that.
Status status = TwitterObjectFactory.createStatus(statusAsString);
status.getClass(); // class twitter4j.StatusJSONImpl
To understand more about why this is done, you can read about static factory methods.
We are building a product that needs to run on production environments. We need to modify some of the functionality of a existing library. The existing library has class's and methods, we need to override 1 or more methods so that the caller uses our overriden methods instead of the original library.
OriginalLibrary
package com.original.library ;
public class OriginalLibrary {
public int getValue() {
return 1 ;
}
public int getAnotherValue() {
return 1 ;
}
}
Original Client
public class MyClient {
private OriginalLibraryClass originalLibraryObject ;
public MyClient () {
originalLibraryObject = new OriginalLibraryClass() ;
System.out.println(originalLibraryObject.getValue()) ;
System.out.println(originalLibraryObject.getAnotherValue()) ;
}
}
Output
1
2
Now, I need to change getValue() to return 3, instead of 1
Needed Output
3
2
package com.original.library.improved ;
public class OriginalLibrary extends com.original.library.OriginalLibrary {
public int getValue() {
return 3 ;
}
public int getAnotherValue() {
return super.getAnotherValue() ;
}
}
If I do the above, I need to tell my Original Client to reorder and use my new com.original.library.improved jar file before com.original.library.
I am almost convinced that this is the most non intrusive way to launch my improved services over and above the OriginalLibrary. I would have preferred a solution where I need to tell the customer to just add my jar file, no need to recompile, relink your client code.
Similar (not same) questions on a google search
here
here
java assist is excellent library for bytecode manipulation. I have modified code below as per your sample code given, You have to explore javaassist more for your actual requirenment
CtClass etype = ClassPool.getDefault().get("com.original.library.OriginalLibrary");
// get method from class
CtMethod cm = etype.getDeclaredMethod("getValue");
// change the method bosy
cm.setBody("return 3;");
etype.rebuildClassFile();
// give the path where classes is placed, In my eclipse it is bin
etype.writeFile("bin");
OriginalLibrary originalLibraryObject;
originalLibraryObject = new OriginalLibrary();
System.out.println(originalLibraryObject.getValue());
System.out.println(originalLibraryObject.getAnotherValue());
Now output of getValue is 3 because I changed body of that method.
A couple of questions -
How is the client getting an instance of your library's class?
If they are using new OriginalLibrary(), then you're pretty much stuck with creating a new subclass of OriginalLibrary and then asking your client to use your new OriginalLibraryImproved class. This is a common problem encountered in projects and is one reason why a library should not allow its clients to instantiate its classes directly using the new operator.
If instead, your client is instantiating OriginalLibrary using a factory method provided by the library (say, OriginalLibrary.getInstance()), you may want to check if there are any hooks into the factory that allow you to change the object being returned.
Do you have full control of the source code of the original library?
If yes, then you definitely should (and I cannot emphasize this strongly enough) provide factory methods for any class in the library that is instantiable. Doing this allows you to change the actual object being returned without modifying the client (as long as the returned object's class is a subclass of the return value from the factory method).
If not, then I suggest you do the following.
Create a subclass of OriginalLibrary (say, OriginalLibraryImproved).
Create a Factory class named OriginalLibraryFactory that has a static method named getInstance(). Write code to return an instance of OriginalLibraryImproved from this method.
Ask your client to replace all occurrences of new OriginalLibrary() with OriginalLibraryFactory.getInstance(). Note that this approach will only involve adding an extra import for the factory class. The client will still refer to the returned instance using the same OriginalLibrary reference as before.
The advantage of this approach is that it gives you complete flexibility to change the implementation details of OriginalLibraryImproved without affecting the client in anyway. You could also swap OriginalLibararyImproved with a newer version like OriginalLibraryImprovedVer2 and the client will be oblivious to the fact that it is using a new class. You'll just have to make sure that OriginalLibraryImprovedVer2 subclasses OriginalLibrary.
An even more flexible approach is to use the Wrapper or Decorator pattern to avoid the pitfalls of inheritance. You can understand more about the Decorator pattern here.
In a nutshell, try to avoid forcing your clients to use new and try to avoid inheritance unless you have very compelling reasons.
I was wondering how people with more experience and more complex projects get along with this "uglyness" in the REST Communication. Imagine the following Problem:
We'll need a fair amount of functionalities for one specific resource within our REST Infrastructure, in my case that's about 50+ functions that result in different querys and different responses. I tried to think of a meaningful resource-tree and assigned these to methods that will do "stuff". Afterwards, the Server Resource Class looks like this:
#Path("/thisResource")
public class SomeResource {
#GET/POST/PUT/DELETE
#Path("meaningfulPath")
public Response resourceFunction1 ( ...lots of Params) {
... logic ....
}
//
// lots of functions ...
//
#GET/POST/PUT/DELETE
#Path("meaningfulPath")
public Response resourceFunctionN ( ...lots of Params) {
... logic ....
}
}
To construct the urls my client will call, I made a little function to prevent Typos and to take better use of Constants
so my Client looks like this:
public class Client() {
public returnType function1 () {
client.resource = ResourceClass.build(Constants.Resouce, "meaningfulPath");
...
return response.getEntity(returnType);
}
}
Now the questions that bothers me is how could I link the client function and the server function better?
The only connection between these two blocks of code is the URL that will be called by the client and mapped by the server, and if even this URL is generated somewhere else, this leads to a lot of confusion.
When one of my colleagues needs to get into this code, he has a hard time figuring out which of the 50+ client functions leads to wich server function. Also it is hard to determine if there are obsolete functions in the code, etc. I guess most of you know about the problems of unclean code better than I do.
How do you deal with this? How would you keep this code clean, maintainable and georgeous?
Normally, this would be addressed by EJB or similar technologies.
Or at least by "real" web services, which would provide at least WSDL and schemas (with kind of mapping to Java interfaces, or "ports").
But REST communication is very loosely typed and loosely structured.
The only thing I can think of now, is: define a project (let's call it "Definitions") which would be referenced (hence known) by client and server. In this project you could define a class with a lot of public static final String, such as:
public static final String SOME_METHOD_NAME = "/someMethodName";
public static final String SOME_OTHER_METHOD_NAME = "/someOtherMethodName";
Note: a static final String can very well be referenced by an annotation (in that case it is considered to be constant by the compiler). So use the "constants" to annotate your #Path, such as:
#Path(Definitions.SOME_METHOD_NAME)
Same for the client:
ResourceClass.build(Constants.Resouce, Definitions.SOME_METHOD_NAME);
You are missing the idea behind REST. What you are doing is not REST but RPC over HTTP. Generally you are not supposed to construct URLs using out of band knowledge. Instead you should be following links received in the responses received from the server. Read about HATEOAS:
http://en.wikipedia.org/wiki/HATEOAS
I currently use Com4j to talk to iTunes from my Java app, unfortunately it does not work with 64bit Java and looks like it never will, so Im trying to use an alternative called Jacob instead.
Both libraries provide a tool to generate Java classes from a DLL, and the resultant classes are very similar and its been straightforward to change most of the code but Im failing on how to find subtypes
IITPlaylist object = itunes.createFolder(TextLabel.SAVE_ITUNES_PLAYLIST_FOLDER.getMsg());
IITUserPlaylist playlistFolder = object.queryInterface(IITUserPlaylist.class);
Both libraries have created IITPlaylist and IITUSerPlaylist classes but only com4j provides the queryInterface class, and no IITUserPlaylist is not actually a subclass of IITPlaylist.
Also com4j provides an is method, but jacob does not
if (next.is(IITFileOrCDTrack.class))
Anyone know how to resolve these issues ?
EDIT:
Made some progress but still not got it working, there is a QueryInterface method that takes the guid of the class (include the curly brackets) , I found the guid by looking at the jacobgenlog.txt file which is created when you run jacobgen on the iTunes executable
This then returns another Dispatch object that is meant to relate to the subclass, however the simple cast Ive done is invalid, whats the mising step ?
private static final String USER_PLAYLIST_GUID = "{0A504DED-A0B5-465A-8A94-50E20D7DF692}";
IITPlaylist object = itunes.createFolder(TextLabel.SAVE_ITUNES_PLAYLIST_FOLDER.getMsg());
IITUserPlaylist playlistFolder = (IITUserPlaylist)object.QueryInterface(USER_PLAYLIST_GUID);
The is() functionality is replaced by checking the kind
IITTrack next = tracks.getItem(i);
if(next.getKind().equals(ITTrackKind.ITTrackKindFile))
A spanner in the works is that jacobgen getKind() methods are invalid Java because they try to return a new interface, and of course you cannot instantiate an interface, so I had to modify them as follows
ITPlayListKind goes from
public interface ITPlaylistKind extends __MIDL___MIDL_itf_iTunesCOMInterface_0001_0081_0001 {
}
to
public enum ITPlaylistKind {
ITPlaylistKindUnknown,
ITPlaylistKindLibrary,
ITPlaylistKindUser,
ITPlaylistKindCD,
ITPlaylistKindDevice,
ITPlaylistKindRadioTuner;
}
Within IITUserPlaylist
public ITPlaylistKind getKind() {
return new ITPlaylistKind(Dispatch.get(this, "Kind").toDispatch());
}
to
public ITPlaylistKind getKind() {
return ITPlaylistKind.values()[Dispatch.get(this, "Kind").getInt()];
}
this wasnt an original idea by me, I got the idea from http://dot-totally.co.uk/software/itunescon/ which appears to be a modified version of the iTunes classes created by jacobgen, I didnt find it added that much and decided to stick with the jacobgen generated classes.
As soon as I set a bounty I work out the answer for myself.
Simply just use the constructor
IITPlaylist object = itunes.createFolder
(TextLabel.SAVE_ITUNES_PLAYLIST_FOLDER.getMsg());
IITUserPlaylist playlistFolder = new IITUserPlayList(object);
The QueryInterface and GUID sctrings re not required.
I was also having a problem working out how to add a track to a playlist, but you just need to
construct a Variant from the track ( I dont have to do this anywhere else)
IITTrack next = itunes.getLibraryPlaylist().getTracks()
.getItemByPersistentID(persistentId.getHighBit(),
persistentId.getLowBit());
playlist.addTrack(new Variant(nextTrack));