If you need flavor you should go to build gradle and add the flavors that you need
Like this
productFlavors {
mock {
applicationIdSuffix = ".mock"
}
prod {}
}
and then you need to create corresponding dir like this /src/prod/java/
How I thought it should work, according to build variant that was choosen for example prodDebug androidStudio will take as a base main source and substitute coresponding classes from dir according to choosen build variant.
But then I found this snippet which said next
Files in the flavor-specific folders do not replace files in the main source set. Trying to do that will result in a duplicate class exception. This is a common misconception because it's how resources are merged.
Ok, so with basic configuration with flavors, you have two kinds of source sets:
main source set
flavor-specific source sets, like your mock and prod
With standard buildTypes configuration (debug and release), this gives you the following build variants (combinations of build types and product flavors):
mockDebug
mockRelease
prodDebug
prodRelease
Each one of them uses every source set that corresponds with flavor/type name and the main set, so for example, the prodRelease will use all of the following source sets at once:
/src/main
/src/prod
/src/release
Effectively, the build system will 'merge' all of these into one source set, and that means if there are classes with the same path and name in these sets, a name clash occurs and compiler will fail.
The way to use source sets correctly is to omit the class that you need to be different for each set from the main set, but instead provide it with all the sets for each flavor / each buildType, for example:
main set has class A.java that references class B.java. B.java is omitted from main set.
Different B.java files are included in mock and prod sets (of course, don't need to be different, but need to provide the same interface, preferably with interface included in main set).
Compiler uses B.java from the set that is being used by the current configuration - build variant, so either the mock or the prod one.
Yay! Now you have two functionally different product flavors.
This behavior doesn't limit to classes, you can use flavor or type specific resources, AndroidManifest.xml files and just about anything that goes into the source dir.
Tip: In Android Studio you can see in the 'project files' section which files will be chosen to compile for a specific variant. To switch build variants, hit Cmd+Shift+A (mac keymap) and search for Build Variants phrase. It usually shows also on the left bottom side of the Android Studio window.
The code from the main source set will always make it into the APK. The source files in other source sets will only be merged if the correct build variant is used. For example, you can create two files:
src/mock/java/yourpackage/MyClass.java
src/prod/java/yourpackage/MyClass.java
Depending on whether you're building prod or mock variant, one of those classes will be compiled and packaged with the APK. Same works for debug and release: you can have code and resources that are only packaged into debug or release versions of the app.
Related
First of all let me put you in context. My main background is Java and I'm working in Python since 2 months ago. I don't know if the approach it's wrong due to my Java background and in Python has a different solution or it's just a technical ignorance problem.
In Java often you have a packaging structure like:
project
|___src
|___main
| |___java/MyClass.java
| |___resources/properties.file
|
|___test
|___java/MyClassTest.java
|___resources/properties.file
Thus, when you execute this from tests (with Maven or IDE):
this.getClass().getResourceAsStream(resourcePath);
Either Maven or IDE loads the test path in the classpath, making test resources available rather than the ones within the main package.
Conversely, when previous line is executed as main, only the resources within the main path are loaded to the classpath.
My question is: Is there any mechanism in Python to simulate this feature? Does Python have other ways to manage resources depending on the execution path?
I think mock might be what you are looking for. It allows for 'mock'ing out external functions to limit the test to strictly the unit under test.
This could mean changing some of the philosophy around some of it. For example, if you want to test that a function is reading a file correctly the filename would get passed to the method as a parameter. In your unit test for the function, pass in a different filename from your test folder.
In another test mock out the open call to the os to check that the method responds as expected when the file is not there, or cannot be opened, or whatever other mis-behaviors you want to test for.
No, Python has no deployable like Java has (WAR, JAR, etc...). You will run your code directly from the source, so, just read the file.
In the Java context, you do not have the code when it is deployed. So every resource should be package inside a file (JAR or WAR).
If you want to find the file in the current folder, look this question.
I don't know very well Python but you are right to ask yourself the question
as separating test and application code makes part of good practice to have a robust/reliable application and tests.
The pytest (a known test framework for Python) documentation explains in its best practice guide the two ways (separating and not separating the test code from the application).
Here is the part referencing the isolated layout :
Choosing a test layout / import rules
pytest supports two common test layouts:
Tests outside application code
Putting tests into an extra directory outside your actual application
code might be useful if you have many functional tests or for other
reasons want to keep tests separate from actual application code
(often a good idea): setup.py
mypkg/
init.py
app.py
view.py
tests/
test_app.py
test_view.py
...
This way your tests can run easily against an installed version of
mypkg.
Note that using this scheme your test files must have unique names,
because pytest will import them as top-level modules since there are
no packages to derive a full package name from. In other words, the
test files in the example above will be imported as test_app and
test_view top-level modules by adding tests/ to sys.path.
If you need to have test modules with the same name, you might add
init.py files to your tests folder and subfolders, changing them to packages: setup.py
mypkg/
...
tests/
init.py
foo/
init.py
test_view.py
bar/
init.py
test_view.py
Now pytest will load the modules as tests.foo.test_view and
tests.bar.test_view, allowing you to have modules with the same name.
But now this introduces a subtle problem: in order to load the test
modules from the tests directory, pytest prepends the root of the
repository to sys.path, which adds the side-effect that now mypkg is
also importable. This is problematic if you are using a tool like tox
to test your package in a virtual environment, because you want to
test the installed version of your package, not the local code from
the repository.
In this situation, it is strongly suggested to use a src layout where
application root package resides in a sub-directory of your root:
setup.py
src/
mypkg/
init.py
app.py
view.py
tests/
init.py
foo/
init.py
test_view.py
bar/
init.py
test_view.py This layout prevents a lot of common pitfalls and has many benefits, which are better explained in this
excellent blog post by Ionel Cristian Mărieș.
https://docs.pytest.org/en/latest/goodpractices.html
I'm going to have a lot of submodules in my main project directory x, like x/module1, x/module2...
can i avoid manually adding every single module into settings.gradle? can i somehow script it to find all the subdirectories and add them automatically?
As cricket_007 already mentioned, Gradle is based on the Groovy programming language (which is, like Java, executed in the JVM) and the settings.gradle file is nothing more but a Groovy script.
Whenever you use include 'project', the include method of a Settings instance is called, so for your goal, you could simply create a loop which iterates over all folders and calls include for each of them.
A more 'groovyesque' approach would be the usage of a closure for each subdirectory, provided by the Groovy SDK extension for the File class:
file('.').eachDir { sub ->
include sub.name
}
There are multiple ways to solve your problem, e.g. since the include method accepts an array of project path strings, you could also aggregate all required paths first and pass them all together. Simply get familiar with the Gradle docs and decide on your own, what solution suits your case the best.
When I'm working in IntellijIDEA how do I tell it to ignore a class file that may have problems and I want to leave dormant for a while?
It will throw errors when I compile whatever class I am working on until I fix the first "dormant" class.
I have tried adding my class to a bogus package but Intellij doesn't like that either because the path doesn't match.
Settings | Compiler | Excludes, add your WIP files there:
You could use Refactor -> Rename File..., and change the file extension.
That is set at the inspection level
Configure Current File Analysis CTRL + SHIFT + ALT + H
I have profiles with differing inspection levels setup loosely based on the phase of my project builds ... I'd suggest taking a look at Customizing Inspection Profiles.
To ignore specific files during compilation you can add files individually or recursively in via the project settings panel ...
Configure Compiler Analysis CTRL + ALT + S :: Compiler => Validation
A bit late, still
If all your files are in the same package, then right-click on the package in the Project tool window and pick "Mark directory as -> Excluded".
All the classes inside the package won't be compiled. You can cancel exclusion any time you want the same way.
Usually, only the classes that are used in the application are actually compiled.
In your case, I would guess that it's only broken unit tests that hinder the compilation (as opposed to any other Java classes in the /main folder).
The reason is this: When running all unit tests in a package or source folder, IntelliJ searches and includes all the files that appear like unit tests by default: those with Test or Suite in the class name, but also those annotated with #Test or #Suite.
So the easiest way to exclude your test is to create a third source folder, call it /ignore, and not mark it as a source folder in IntelliJ. You can then drop any file you don't want to include in your compilation there temporarily, and drag it back to its original folder when you want to continue working on it. Beware, though: You will get only limited tool support if you open and edit the file within an unmarked source folder, so it should really be used for "parking" only.
You could also change the file extension, as the other answer suggests, but then IntelliJ will also change its handling of the file in other respects, not just during compilation.
Also, if you're using JUnit 4, you can always annotate any single test method, or the entire test class, with #Ignore, and it will be skipped during the test run. This requires the class to be formally correct, though, i.e.: no compile time errors.
P.S: You need to actually move the test to a different folder, if you really want the package to change - not just edit the package declaration. Otherwise, a non-matching declaration will also be considered an error.
Can anyone explain how identical Java sources can end up compiling to binary differing class files?
The question arises from the following situation:
We have a fairly large application (800+ classes) which has been branched, restructured then reintegrated back into the trunk. Prior to reintegration, we merged the trunk into the branch, which is standard procedure.
The end result was a set of directories with the branch sources and a set of directories with the trunk sources. Using Beyond Compare we were able to determine that both sets of sources were identical. However, on compiling (same JDK using maven hosted in IntelliJ v11) we noticed that about a dozen or so of the class files were different.
When we decompiled the source for each pair of apparently different class files we ended up with the same java source, so in terms of the end result, it doesn't seem to matter. But why is it that just a few of the files are different?
Thanks.
Additional thought:
If maven/javac compiles files in a different sequence, might that affect the end result?
Assuming that the JDK versions, build tool versions, and build / compilation options are identical, I can still think of a number of possible sources of differences:
Timestamps - class files may1 contain compilation timestamps. Unless you run the compilations at exactly the same times, different compilations of the same file would result different timestamps.
Source filename paths - each class file includes the pathname of the source file. If you compile two trees with different pathnames the class files will contain different source pathnames.
Values of imported compile-time constants - when a class A uses a compile-time constant defined in another class B (see JLS for the definition of a "compile time constant"), the value of the constant is incorporated into As class file. So if you compile A against different versions of B (with different values for the constants), the code of A is likely to be different.
Differences due to identityHashcode being used in HashMap keys by the compiler could lead to differences in map iteration order in some step. This could affect .class file generation in a way that is not significant, but still shows up as a .class file difference. For example, constant pool entries could end up in a different order.
Differences in signatures of external classes / methods; e.g. if you changed a dependency version in one of your POM files.
Differences in the effective build classpaths might result in differences in the order in which imported classes are found. This might in turn result in non-significant differences in the order of entries in the class file's Constant Pool. This could happen due to things such as:
files appearing in different order in the directories of external JAR files,
files being compiled in different order due to the source files being in different order when your build tool iterates them2, or
parallelism in the build (if you have that enabled).
There is a possible workaround for the problem with file ordering: use the undocumented -XDsortfiles option as described in JDK-7003006. (Kudos to #Holger for knowing about that.)
Note that you don't normally see the actual order of files in file system directories. Commandline tools like ls and dir, and file browsers will typically sort the entries (in name or timestamp order) before displaying them.
1 - This is compiler dependent. Also, it is not guaranteed that javap will show the timestamps ... if they are present.
2 - The OS gives no guarantees that listing a directory (at the syscall level) will return the file system objects in a deterministic order ... or the same order, if you have removed and re-added files.
I should add that the first step to identifying the cause of the differences is to work out exactly what they are. You probably need (needed) to do that the hard way - by manually decoding a pair of class files to identify the places where they actually differences ... and what the differences actually mean.
When you compare using beyond compare, comparision is done based on contents of the files. But in the build process just the timestamp of the source files are checked for change. So it your source file's lastmodified date changes it will be recompiled.
Different JDK produce different binary classes (optimizations, but also class version number). There are compilation options, too (a JDK may compile in an older format, or it can add debug information).
Different versions of Java can add different meta data which is often ignored by a decompiler.
I suggest you try using javap -c -v for more of the details in a file. If this doesn't help you can use the ASMifierClassVisitor which looks at every byte.
same JDK can also have different output depending on how you compile.
you can compile with or without debug info, you can compile to run in an older version, each option will result in other classes.
First of all: I'm not entirely familiar with Java, and the few things I know I have learned while playing with Java.
However, there is something I have noticed in pretty much any Opensource Java project - the use of alot of subdirectories for the sources, which usually look like so:
./src/main/java/com/somedomainname/projectname/sourcefile.java
Now, why so many subdirectories? what's the deal with the domainname?
The domain name is used for the package name - so that file would be for the class
com.somedomainname.projectname.sourcefile
where com.somedomainname.projectname is the package.
Conventionally, source file organization mirrors the package layout. The normal Java compiler doesn't actually enforce directory structure (although some IDEs such as Eclipse will complain if you put things in the "wrong" directories) but it does force public classes to be in a file with the same name. Non-public classes can go in any file, but conventionally the filename matches the class name there, too. It makes it very easy to navigate to any class without any prior knowledge.
The Java language specification doesn't say that a compiler must enforce the convention for public classes; it explicitly says that it can though. See section 7.2 of the JLS for more details.
This directory structure is used as a convention that shows where the library is from and separates it from other sources.
One reason to use this structure is that is the standard used by Maven.
Maven is a build tool that helps to manage the dependencies of a project. Maven is designed for convention over configuration, so you will often see this directory structure to make it work with Maven.
Maven specifies that the directory structure start with /src/main/java for Java files, and the rest is based on the naming convention for namespaces.
The use of the domain name in the path is to prevent class collisions. If 2 different libraries both supply a class with the same name, the domain name namespace allows them to both be used.
A Java package is a mechanism for
organizing Java classes into
namespaces similar to the modules of
Modula. Java packages can be stored in
compressed files called JAR files,
allowing classes to download faster as
a group rather than one at a time.
Programmers also typically use
packages to organize classes belonging
to the same category or providing
similar functionality.
...from http://en.wikipedia.org/wiki/Java_package
subdirectories as an organizational tool so that you don't just have one directory with tons of java files. The reason you often see a domain name is that conventionally people derive java package names from their domain names in order to prevent collisions with other developers. So although we both might have a util.Stringutil class, if I name mine com.mydomain.util.Stringutil and yours is com.yourdomain.util.Stringutil, we can have a project containing both classes without a collision.
There is an interesting read on java packages and directories in the newer O'Reilly book Java: The Good Parts (starting at the bottom of page 46).
...the required interaction between the package system and the filesystem
is both regrettable and a pain...
This is meant as a standard to define unique locations for java source code. It is convention to follow this package structure, which is why you see it everywhere. It's not required to do it that way - you can name your packages whatever you want. It is very commonplace to follow this convention, however.
package prefix.organization.project.ClassName;
package prefix.organization.project.package.ClassName;
package prefix.organization.project.package.subpackage.ClassName;
When storing Java source code files, each part of the package name translates into a subdirectory. So the same three classes shown above would be located in the corresponding directories off the main classpath.
prefix/organization/project/ClassName.java
prefix/organization/project/package/ClassName.java
prefix/organization/project/package/subpackage/ClassName.java
When compiling by hand, be sure that the main classpath directory is the current directory or is within the classpath in order that the source code files can be found.
As for the src/main/java part of it, it seems this comes from Maven. I've never used that software. I don't understand why they would need so many, since my projects (I use Eclipse) just have a src folder there instead.
./src/main/java/com/somedomainname/projectname/sourcefile.java : Decomposed
src/main/java
this is the directory that needs to be passed to the javac compiler stating where the source code for compilation can be found.
1.1 src/test/java
this is where the unit test classes should be kept.
1.2 src/main/resources and src/test/resources
these are the corresponding directories where resources such as properties files should be kept.
1.3 Separate output directories.
main and *test * classes and resources should be compiled to their own separate output directories. Maven uses target/classes and target/test-classes. When you jar your compiled class files for distribution, you don't want to include test classes and test resource files.
com/somedomainname/projectname
this directory structure corresponds to the package declaration in the classes found in projectname i.e. package com.somedomainname.projectname
SourceFile.java corresponds to the class name that it defines, and it should by convention start with an uppercase character see http://www.oracle.com/technetwork/java/codeconvtoc-136057.html
Also in the link above you will find out that the default package naming convention uses the domain name in reverse.
The Java Language Specification defines a package naming convention that says that package names should include a domain name, as it provides a globally-rooted namespace.
The source files need to be in subfolders that match the package name, because the Sun Java compiler, javac, enforces strongly encourages it. Additionally, many other build tools and IDEs also either strongly encourage or require that the source .java files are stored in paths that match the package.