I have two Android apps that are identical except for the package name. This question has been asked before, and the recommendation was to refactor the package name as required, but I do not regard this as satisfactory. To my mind putting all the code in a source library would be preferable, but is there a better solution?
Putting the shared code in a Library Project is the recommended approach. See http://developer.android.com/guide/developing/projects/projects-eclipse.html#SettingUpLibraryProject
I take it the question is "How to I build both apps without duplication?" An easy answer: have your build system perform the duplication and package alteration for you. And one way to accomplish this even if you're used to letting Eclipse or ant handle everything in ways opaque to you:
make a temporary copy of your entire repository, with the original building only one of your apps.
make all the changes to the copy that will cause it to build your second app.
create a single .patch that expresses these changes.
have your build system perform step #1, apply the patch from step #3, and then reinvoke itself in the copy. "have your build system" means, write a script, add a target to a makefile (even if you normally avoid makefiles), add a target to ant, extend Eclipse, whatever.
Related
I am writing here because of desperation caused by refactoring a GWT project.
My first try:
After I read all the praises of the refactoring tool from Eclipse ( I am using it as IDE) I simply right clicked on a module ( what a fool i was ) and use the refactoring option. My project became unusable.
First Conclusion:
Found out that I need to start with the classes and then go up and refactor a module at a time.
Second try:
Refactored some classes, worked fine until I messed something related to a ui.xml file. Project unusable!
Second Conclusion:
Be careful at the ui.xml files!
Third try:
Went pretty well, but I got ahead of myself and tried to remove some comments or replace class names in comments. Predictable result : project unusable!
Third Conclusion:
Try again!
Forth try:
Fail!
Fifth try:
Fail!
You get the picture.
Can someone experienced with GWT please offer some guidelines about the mystical realm of refactoring?
GWT has some rules based on naming conventions (e.g. the two interfaces for GWT-RPC, the *.ui.xml files and the class that uses them through UiBinder, the files related to ClientBundle or ImageBundle methods, the *.properties files for I18N), so failing to respect them when renaming/moving one class/file will break it.
GWT also sometimes references classes by name in non-Java files (#eval in the *.css of a CssResource, or in *.ui.xml files), non-Java portions of classes (JSNI) or string literals (e.g. in #ProxyForName and #ServiceName). Failing to update them all will break the build.
Because a tool makes it easy to refactor does not mean you should let it do it blindly: it's just a tool, you have to understand what it does and double-check it (hint: check the box in Eclipse that forces a preview before applying the refactoring) so it doesn't do too much or too few.
I have a Swing/Java application that is being used for clients and has weekly updates.
The problem is the setup just lay out the classes and their respective directories and on the update I just update the classes.
I want to do a single jar containing all the classes, but I'm not sure how would I be able to update it...
Also some clients need some updates during the week where only one or two classes would be updated.
What is the right way of doing this ?
Im using Eclipse.
EDIT: I know how to create the jar, I just dont know how to dynamically update it.
I would suggest you look into Java WebStart which is designed to do exactly what you need.
You need to first create the finished deployment and then you can look into creating a JNLP file for the deployment, and a way to put all the files to a web server for the user to access. For now just let the user download the whole thing every time you update. When you get more experienced you can look into how you can make incremental updates.
I would strongly recommend including a build number or timestamp in the deployment paths so a jar file is not cached incorrectly in the client by accident.
The general way of doing this, even if only small changes were made, would be to repackage your JAR after each update and give that JAR to a user. The user would replace the existing JAR. How you produce your JAR is up to you. Many IDEs support it, you could write a shell script, use existing build systems like ant or maven or even make, whatever. (See edit below)
If your JAR is very large and deployment is cumbersome, you may be able to split your project into smaller subcomponents, each with their own JAR, and only redistribute the ones containing changes. That may or may not be a major refactoring for you, and it might not even be appropriate. For most small or average size projects, this is generally unnecessary.
As for deployment, there are also a zillion ways to make that easier on the user. You could just give them a JAR file. You could use e.g. install4j. You could use Java Web Start (although its kind of clunky). There are others.
Both install4j and JWS support automatically checking for updates. If you choose to support that feature, all you would need to do is update your distribution site, and users would receive updates automatically. That's also up to you.
But a short answer to your question is: If you have all of your classes packaged in a JAR, no matter how many classes change, you'll want to give the entire updated JAR to the user. The benefit that counters this cost is that a JAR is a nice, compressed, self-contained collection of your application/library's source, which makes management and deployment very convenient.
Edit: Responding to your edit where you specify that you are using Eclipse, Josh M gives you instructions in his comment on your answer. To add to his comment, to export a Runnable Jar you'll have to have a Run Configuration set up which, if you've been running your application in Eclipse already, you probably already have. If not you can create one in the Run menu.
Edit 2: Please refer to Thorbjørn Ravn Andersen's answer as well for some good JWS tips.
I know that there is the option to have links to source code under your src directory instead of having the source code files directly in your Eclipse project.
When is this case i.e. links for source code is best used?
I always found it more convenient to have the source code inside the Eclipse project
I can think of two possible use cases for this.
The first would be if you want to keep your source and IDE meta-data separate. For example it may be that some developers use Eclipse and some IntelliJ. In this case you would probably only want the source of the project to be stored in SCM, as otherwise, one set of developers are going to have to remove meta-data before importing the project. If they just link to the source, they can maintain there own meta-data for there IDE. Obviously this isn't an issue if everyone uses the same IDE.
The second use case would be dependencies. Say for example your working on two different projects A and B where A depends on B. If your not using a dependency management tool or willing to build and import the Jar from B to A each time you modify it, you could link to the source in B instead.
I'm sure there are plenty of other use cases floating around.
In addition to what Kingamajick mentions, you could have a structure that causes overly long path names.
Windows can only handle so much (256 characters? in older versions), and a deep package structure easily breaks that limit.
So, having your classes in a shallow directory near the top allows you to have your workspaces deeper down, and still leaves some room to wiggle.
Other scenarios; You have source code which is common for several OS:es, but the Eclipse projects are specific for each OS.
You can also create a form of linked resources that are relative to an environment variable. I've used that for situations where the version control system (ClearCase) adds user-specific catalognames.
The problem scienario is as follows (Note: this is not a cross-jar dependency issue, so tools like JarAnalyzer, ClassDep or Tattletale would not help. Thanks).
I have a big project which is compiled into 10 or more jar artifacts. All jars depend on each other and form a dependency hierarchy.
Whenever I need to modify one of the jars, I would check out the relevant source code and the source code for projects that depend on it. Modify the code, compile, repackage the jars. So far so good.
The problem is: I may forget to check one of the dependent projects, because inter-jar dependencies can be quite long, and may change with time. If this happens some jars may go "out-of-sync" and I will eventually get a NoSuchMethodException or a some other class incompatibility issue at run-time, which is what I want to avoid.
The only solution I can think of, the most straighforward one, is to check out all projects, and recompile the bunch. But this takes time, especially if I re-build it every small change. I do have a continuous integration server, that could do this for me, but it's shared with other developers, so seeing if the build breaks is not an option for me.
However, I do have all the jars so hypothetically it should be possible to verify jars which depend on the code that I modified have an inconsistency in method signature, class names, etc. But how could I perform such check?
Has anyone faced a similar problem before? If so, how did you solve it? Any tools or methodologies would be appreciated.
Let me know if you need clarification. Thanks.
EDIT:
I would like to clarify my question a little bit.
The ultimate goal of this task is to check that the changes that I have made will compile against the whole project. I am looking for a tool/technique that would aid me perform such check.
Consider this example:
You have 2 projects: A and B which are deployed as A.jar and B.jar respectively. A depends on B.
You wish to modify B, so you check it out and modify a method signature that A happens to depend on. You can compile B and run all tests by itself without any problems because B itself does not depend on anything. So you happily commit your changes.
In a few hours the complete project integration fails because A could not be compiled!
How do I avoid this?
The kind of tool I am looking for would retrieve A.jar and check that all dependencies in A on the new modified B are still fine. Like a potential compilation error that would happen if I were to recompile A and B sources together.
Another solution, as was suggested by many of you, is to set up a local continuous integration system that would recompile the whole project locally. I don't mind doing this, but I want to avoid doing it inside my workspace. On the other hand, if I check-out all sources to another temporary workspace, then I need to mirror my local changes to the temporary workspace.
This is quite a big issue in my team, as builds break very often because somebody forgot to check out (or open in Eclipse) the right set of projects. I tried persuading people to check-out source and recompile the bunch before commits, but not only it takes time, it needs running quite a few commands so most people just find it too troublesome to do. If the technique is not easy or automated, then it's unusable.
If you do not want to use your shared continuous integration server you should set up a local one on your developer machine where you perform the rebuild processes on change.
I know Jenkins - it is easy to setup (just start) on a local machine and I would advice to run it locally if no one is provided in the IT infrastructure that fits your needs.
Checking signatures is unfortunately not enough. Having the correct signatures does not mean it'll work. It's all about contracts and not just signatures. I mean what happens if the new version of a library has the same method signature, but accepts an ArrayList parameter now in reversed order? You will run into issues - sooner or later. I guess you maybe consider implementing tools like Ivy or Maven:
http://ant.apache.org/ivy/
http://maven.apache.org/
Yes it can be pain to implement it but once you have it it will "guard" your versions forever. You should never run into such an issue. But even those build tools are not 100% accurate. The only proper way of dealing with incompatible libraries, I know you won't like my answer, is extensive regression testing. For this you need bunch of testing tools. There are plenty of them out there: from very basic unit testing (JUnit) to database testing (JDBC Proxy) and UI testing frameworks like SWTBot (depends if your app is a web app or thick client).
Please note if your project gets really huge and you have large amount of dependencies you always not using all of the code there. Trying to check all interfaces and all signatures is way too much. Its not necessary to test it all when your code use lets say 30 % of the library code. What you need is to test what you really use. And this can be only done with extensive regression testing.
I have finally found a whole treasure box of answers at this post. Thanks for help, everyone!
The bounty goes to K. Claszen for the quickest and most input.
I'm also think that just setup local Jenkins is a best idea. What tool you use for build? Maybe you can improve you situation with switching to Maven as build tool? In more smart and don't recompile full project if you don't ask it directly. But switch to in can be HUGE paint in the neck - it hardly depends on how you project organized now...
And about VCS- exist Mercurial/SVN bridge - so you can use local Mercurial for you development ....
check this link: https://www.mercurial-scm.org/wiki/WorkingWithSubversion
There is a solution, jarjar, which allows to have different versions of the same library to be included multiple times in the dependency graph.
I use IntelliJ, not Eclipse, so maybe my answer is too IDE-specific. But in IntelliJ, I would simply include the modules from B into A, so that when I make changes to A, it breaks B immediately when compiling in the IDE. Modules can belong to multiple projects, so this is not anything like duplication, it's just adding references in the IDE to modules in other projects.
I currently have a java library in subversion under package:
com.company.product.foo.*
Unfortunately, I have to refactor this into:
com.othercompany.bar.*
That'd be fine as a one-shot. But this has to be performed only on a specific branch. The problem is then to merge changes from trunk to the branch with totally different names.
The only solution I see would be to create a patch file, run some search & replace and then apply it on the branch.
Is there any better option ?
The first most obvious solution is to not use either company name as the package, but rather a trademarked name, or a neutral domain name that would be used going forward.
If that isn't possible (as in the customer doesn't want the two code bases to be seen as connected) the next most obvious solution is to use a source control system that is more friendly to the concept. Git might have better options, or perforce.
If you have to stick with subversion, then I would have it in source control under a neutral package name and then have the build process that checks out the code, moves it, renames the packages, and compiles, once for each company. Or If your IDE can understand it use a Java pre-processor.
Of course, that last one only works if both customers stay on the same base, but if not then the customer would have its own branch, and the build process could copy the code only as appropriate for the correct branch.
I can't see any really good solutions, but would it be an option to just create subclasses under the new package name?
Then the patches could be applied to the super classes, and the sub classes would never actually contain anything.
A good IDE with refactoring capability will be able to handle this in an instant. Once you make the change, commit it to Subversion. One of its strengths is that it treats directories and files the same way, so you can keep the history as you rename packages.
Sounds like you'd want to create a tag for the original; check out and refactor the trunk; commit the changes. Voila - old and new, with the refactored packages on the trunk where they belong.
Perhaps I'm misunderstanding your question, but I don't think you should make the change directly inside Subversion. Change the code and let Subversion do its job.