I have two projects:
A project
B project (lists A as one of B's dependencies)
A has a method that relies on A's resource
When B calls A's method, A ends up access B's resource folder and thus is unable to find A's own resource files.
Any way around this?
In order to ensure that a project will always access its own resources, you need to load them using the Class#getResource method.
Example:
public class MyCalledClass{
public static void loadResource() {
new File(MyCalledClass.class.getResource("file.txt").getPath()); // Will retrieve the file called "file.txt"
// in the project where this class is
new File("file.txt"); // Will retrieve the file called "file.txt" in the project calling this method
}
}
Related
I have multi-module project under SBT.
Project A (library) has reference.conf file with A's configuration parameters. Project A depends on akka-actor library, which ships with its own reference.conf file. Project A redefines some akka's parameters in own reference.conf.
Project B depends on A.
When I call ConfigFactory.load() in B, I'm getting wrong order of reference.confs merging. It first takes A's config, then applies akka-actor's config over it. Eventually, I'm getting initial akka-actor's configuration.
How can I fix it? I need to get akka-actor's config loaded first, then my A's config should be applied over it.
Ok, looks like I've found the answer in sources of ConfigFactory.
All the reference.conf is being loaded through ClassLoader.getResources. It returns java.util.Enumeration[URL]. The order of URLs in this enum is the answer to the question. So all you need to do: ensure the order of your reference.conf resources in this enumeration properly arranged.
Here is an example of how to do that. First, create your own version of ClassLoader by overriding getResources method:
import scala.collection.JavaConverters._
class CustomClassLoader(loader: ClassLoader) extends ClassLoader(loader){
override def getResources(name: String): util.Enumeration[URL] = {
val resources = super.getResources(name).asScala.toList
// arrange resources as you wish here
java.util.Collections.enumeration(resources.asJava)
}
}
Last, call load method of ConfigFactory with your CustomClassLoader instance.
I am having a problem with a circular dependency. Similar question have been asked and I have read a lot of answers. Most deal with a work-around but I would like to refactor so what I have it correct and I would like some input on where I have gone wrong. I can change what I am doing but not the entire project architecture.
I am using VB.Net in Visual Studio 2012.
I have two class libraries:
DataLayer for accessing the database.
DataObject which contains classes that represents my business objects.
My Presentation Layer calls methods in the DataLayer which returns objects from the DataObject class library.
(I have simplified somewhat – I actually have a controller layer but it needs references to the two class libraries above. This is an existing architecture that is from before my time.)
In the DataObject class library I have an abstract class that represents a file. It has properties such as filename, userID, etc. It also has a method, GetFile(), that I code in the derived classes because there are different ways of getting the file. A DataLayer method returns a collection of these file objects, but I don't want to get the actual file until it's needed.
So far, I have a derived class that calls a webService (using properties from the baseClass) and a derived class that accesses the fileSystem. Both return a byte array representing the file. The calling class does not need to know how the file is retrieved.
Now I have a new requirement to build the file on the fly using data from the database. I can get all the data I need using the properties in the base class.
My issue is that my GetFile() method will need to access my DataLayer class library to pull data from the database which causes a circular dependency. The DataLayer class library has a reference to DataObject since that is what it returns. But now I need to call the DataLayer from a class in DataObjects.
I could call the DataLayer from presentation and pass the result to
my DataObject’s GetFile() method, but then my presentation layer
needs to do something special for this derived class. My goal is
that the derived class handles GetFile without presentation knowing
about the implementation.
I could create a new class library for this DataLayer code but I
don't like a special case.
I could access the DB directly in the DataObject class but that
circumvents the layered architecture.
I can’t change our architecture, but I can change my approach.
Any opinions?
I think I have the answer.
In my concrete class, when I am loading the data initially (in the DataLayer), I will get all the data I need to create the file. I'll store it in a new property in my concrete class which my GetFile() method will use to build the file.
This has a little more overhead - I make DB calls and put all this data in memory when it may not be needed. I'll give it a try and see how performance is.
Any critiques of this approach?
I am writing my own logging class to save data in a DB. As I looked how CI is doing I noticed there is a log_message() function which handles the logging. There is a load_class function I can't assign to anything in the CI user guide.
1 Why do they put this into an extra function?
2 What/where loads this function files from?
Hope there are some CI guys how can answer :-)
Short answer:
You can write your own log class to override the default CI class:
<?php
// this file is /application/libraries/MY_Log.php
class MY_Log extends CI_Log {
public function write_log($level = 'error', $msg, $php_error = FALSE)
{
// Put your own logging function in here.
// If you want it to still log to a file as usual, use this:
parent::write_log($level, $msg, $php_error);
}
}
Long answer:
The load_class() function is basically a singleton loader. If the class has already been loaded, return a previous instance; otherwise, load it and create the singleton. It is very important in a framework like CI. You have to know that every time you call, say, a database function, it is applying it to the same object, not instantiating a new one (that would get really messy). All CI libraries function this way by default.
An important note: they changed how this functions significantly in version 2.0. Previously, it would only load from the /libraries folder, but now, it will load from /core or wherever you specify when calling the function.
Here's the process for loading, say, the Log class (from your example):
$_log =& load_class('Log');
$_log->write_log($level, $message, $php_error);
This runs the following checks, in sequence:
If the Log class already exists, we're done. Return the singleton.
If not, first check the /system/libraries folder for a "Log.php" file
If no file existed for step #2, now check /application/libraries for a "MY_Log.php" file (or whatever your subclass prefix is set to in your configuration)
If it loaded the default CI class (from the /system folder), but you DO have an extended class under /application, load that class too.
Return a new instance of the class (YOURS if it exists; otherwise, it's the CI_* class)
I've actually never needed to use the load_class() function, as it allows extension fairly seamlessly. However, it's good to know how it works.
So, to override a class, first find where the original resides (usually /system/libraries or /system/core). Put your extending file in the corresponding /application folder (this is important! If it's under /system/core, the extension MUST be under /application/core). Prefix both the filename and the class name with MY_ (or whatever you set in your configuration), and have it extend the CI_ base class.
I had
class Voo
{
private static AnotherClass Doo(int id)
{
//do some stuff with id then return object of AnotherClass
return x[0];
}
}
and used this private with moles
MVoo.DooInt32 = delegate ...
NOW I changed the method to:
class Voo
{
private static AnotherClass Doo(string a, object b)
{
//do some stuff with a and b then return object of AnotherClass
return x[0];
}
}
BUT moles does not give me the new signature. Sill MVoo.DooInt32
but I expect MVoo.DooStringObject
I removed the moles reference, cleaned, rebuilded. No positive result so far.
Any Ideas?
You need to be sure to delete the mole assembly file (.dll), rebuild the test project without the mole type, and then add it back in. This process is thorough, and has always worked for me, in this situation:
Remove the mole assembly reference from the test project
Delete the .moles file, named after the assembly in question
In Solution Explorer, show all files in the test project
Expand the hidden "MolesAssemblies" folder
Delete the desired _.Moles.dll file and corresponding XML files
Remove (not delete) test files that reference the mole assembly
Rebuild the test project
Select the "Add Moles Assembly" context menu option, on the desired test project reference
Add test files that were temporarily removed from the project
Rebuild the test project
You have to delete your moles file for that assembly something like voo.moles and then create a new one.
I have a number of test classes and methods that copy a particular directory like so:
[TestClass, DeploymentItem("LanguageData", "LanguageData")]
public class OcrTests
{
[TestMethod]
public void Can_Capture_Field()
{
// some code that expects the LanguageData directory to be in the test results Out directory
}
// etc
}
[TestClass]
public class OcrBuilderTests
{
[TestMethod, DeploymentItem("LanguageData", "LanguageData")]
public void Can_Build_Specific_Ocr_Engine_Implementation()
{
// some more code that expects the LanguageData directory to be in the test results Out directory
}
// etc
}
Those tests are in a single assembly and all the files in the LangaugeData directory have their Copy to Output Directory set to Copy Always.
It all works fine and the directory is copied to the test results Out directory as long as I only have that one test assembly loaded into the solution or that's the only assembly I run tests from (i.e. run tests only in current context/class).
As soon as I add a second assembly and run all the tests in the solution then that directory no longer gets copied, but any other DeploymentItems that are just individual files seem to get copied fine.
The tests themselves all still run, but the ones that depend on that directory crash. Presumably that's because MSTest can't find the directory - perhaps it's expecting it to be in the build directory of one of the other test assemblies?
Any ideas what it is about multiple test projects that's preventing the copy, and what I can do to get around it, short of adding every single file in that directory as an individual DeploymentItem?
This question is quite old, but could still benefit others. Especially since I ended up here :)
It seems that DeploymentItemAttribute doesn't support using the same source path name in multiple test classes.
Note: I said same path name, not physical folder (think different test projects with same folder name to deploy).
However the destination folder name can be different, with no ill effects.
My suggestion is:
Create a fixture base class (if you prefer, in separate project)
Add the attribute: [TestClass, DeploymentItem("LanguageData", "LanguageData")]
Change your OcrTests and OcrBuilderTests classes to inherit the new class.
Remember to remove the deploymentitem attributes for 'LanguageData' from OcrTests and OcrBuilderTests
I've tried this, with Great Success.
In my case, I had a common test fixture project and multiple test projects, each using the base class.
Unfortunately the DeploymentItemAttribute is filled with Gotchas, see here for more.
Tried your approach but still it did not copy folder properly, so what i did instead copied files not directories(maybe this helps someone):
[TestClass]
[DeploymentItem("connectionStrings.config")]
// should be able to do this, but it does not work always, only sometimes
//[DeploymentItem("Configs", "Configs")]
// this instead should work always
[DeploymentItem("Configs\\file1.txt", "Configs")]
[DeploymentItem("Configs\\file2.txt", "Configs")]
[DeploymentItem("Configs\\file3.txt", "Configs")]
.....
[DeploymentItem("Configs\\filen.txt", "Configs")]
public class BaseTests
{
}