I have created a default class file for handling the xpath under default package,
public class TestObjectHelper {
/*
* TestObjectHelper will help the user to handle dynamic xpath
*/
public static TestObject getTestObjectWithXpath(String xpath) {
return new TestObject().addProperty('xpath', ConditionType.EQUALS, xpath)
}
}
I want to use it another package, but it is not identifying the above method.
import statement
You need to call the function the following,
import TestObjectHelper
or suggest to move this under a separate package let's call it as com.utilites
import com.utilites.TestObjectHelper
Related
Is there a cool way to add sql comment like below on Mybatis.
SELECT * FROM users; /* TraceID: foo-bar-baz */
I would like to add sql comment with TraceID/RequestID/CorrelationID in the context of distributed tracing to all executed sql.
This comment enables to identify a transaction from the comment of a slow query.
I found Interceptor API, but I seem that cannot add commnet.
I seem that we can use scripting like thymeleaf-scripting in this way.
But, We need to add sql comment in all sql...
Any advice will be appreciated.
In your case, a custom language driver might be a good fit.
Implementation
The below implementation is mostly the same as the default XMLLanguageDriver.
import org.apache.ibatis.builder.xml.XMLMapperEntityResolver;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.parsing.PropertyParser;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.parsing.XPathParser;
import org.apache.ibatis.scripting.defaults.RawSqlSource;
import org.apache.ibatis.scripting.xmltags.DynamicSqlSource;
import org.apache.ibatis.scripting.xmltags.TextSqlNode;
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
import org.apache.ibatis.session.Configuration;
public class CommentLanguageDriver extends XMLLanguageDriver {
#Override
public SqlSource createSqlSource(Configuration configuration,
XNode script, Class<?> parameterType) {
// Append comment
script.getNode().setTextContent(
script.getNode().getTextContent() + getComment());
return super.createSqlSource(configuration, script,
parameterType);
}
#Override
public SqlSource createSqlSource(Configuration configuration,
String script, Class<?> parameterType) {
if (script.startsWith("<script>")) {
XPathParser parser = new XPathParser(script, false,
configuration.getVariables(), new XMLMapperEntityResolver());
return createSqlSource(configuration,
parser.evalNode("/script"), parameterType);
} else {
// Append comment
script = PropertyParser.parse(script + getComment(),
configuration.getVariables());
TextSqlNode textSqlNode = new TextSqlNode(script);
if (textSqlNode.isDynamic()) {
return new DynamicSqlSource(configuration, textSqlNode);
} else {
return new RawSqlSource(configuration, script, parameterType);
}
}
}
private String getComment() {
// OGNL expression invoking the static method
return " /* ${#org.slf4j.MDC#get(\"requestid\")} */";
}
}
The appended comment contains an OGNL expression invoking the static method.
This expression is evaluated at runtime.
Configuration
To register the custom language driver globally, you need to set defaultScriptingLanguage in the config.
<settings>
<setting name="defaultScriptingLanguage"
value="pkg.CommentLanguageDriver" />
</settings>
If you are using mybatis-spring-boot-starter, add the following line to your application.properties.
default-scripting-language-driver=pkg.CommentLanguageDriver
I'm trying to debug a library which uses haxe.macro.TypeTools::findField. I've created a simple code for that:
package;
using haxe.macro.TypeTools;
class Main
{
public function new()
{
var test = findField(Child, "hello");
trace(test);
}
}
class Base
{
private function hello()
{
}
}
class Child extends Base
{
public function new() {}
}
However I'm getting error Unknown identifier : findField. Is this because it can only be used in build macro context?
This is what I'm trying to emulate.
First of all, function findField() is not from the haxe.macro.TypeTools.
It is a helper function from edge.core.macro.Macros.
To use it without a class path, import it's class with a wildcard import edge.core.macro.Macros.*
Secondly, findField() should be used in a build macro context only, since it expects Array<Field>, which is obtained by haxe.macro.Context.getBuildFields().
Lets assume i have a class which has the same name as an previously defined type which is defined inside lib.d.ts. How would i make use of that type within this class.
For example, i have the class Event, which has to deal with the browsers Event object, which is defined as an interface in lib.d.ts.
export class Event { // own definition of Event which hides original Event
public dealWithBrowserEvent(event: Event): void { // Event object defined by lib.d.ts
// deal with it
}
}
How would i tell Typescript that this are two different types. Of course i could simply rename my class, but i don't want to do that, because the name is perfect for my use case.
You can archive this by doing so:
E.ts:
class CustomEvent
{
public dealWithBrowserEvent(event: Event): void
{
}
}
export default CustomEvent;
A.ts:
import Event from './E'
export class SomeClass
{
//Parameter e here is instance of your CustomEvent class
public someMethod(e: Event): void
{
let be: any;
//get browser event here
e.dealWithBrowserEvent(be)
}
}
More on declaration merging, and what can be merged and what not: link
I strongly recommend you not doing so. This code will lead to a lot of confusion for your colleagues reading/modifying it later, let alone headache of not being able to use in the same file standard class for Event.
In the meantime i found a quite doable solution. I defined an additional module which exports renamed interfaces. If i import this module, i can use the renamed types as if they would be original types.
browser.ts
// Event will be the one from lib.d.ts, because the compiler does not know anything about
// the class Event inside this module/file.
// All defined properties will be inherited for code completion.
export interface BrowserEvent extends Event {
additionalProperty1: SomeType;
additionalProperty2: SomeType;
}
If you don't need additional properties you can just do type aliasing:
browser.ts
// Alias for Event
export type BrowserEvent = Event;
event.ts
import {BrowserEvent} from './browser.ts';
export class Event { // Definition of Event hides original Event, but not BrowserEvent
public dealWithBrowserEvent(event: BrowserEvent): void {
// deal with it
}
}
I'm quite happy with this solution, but maybe there is a even better solution.
How do I create a template that each time when I create a class that extends MyClass, it will automatically add 3 functions.
EDIT:
In other words I am trying to implement Abstract functionality in AS3. Assume that MyClass have both private and protected methods.
I see the only way to write own code template and call it every time you need, in Flash Builder: window->preference->flash builder->editors->code template->action script->new and give the name to the template, for instance myclass.
You can use existed templates as an example for template syntax.
Template code for MyClass child class with three methods:
import my.package.MyClass
/**
* #author ${user}
*/
public class ${enclosing_type} extends MyClass
{
public function ${enclosing_type}()
{
}
override public function publicMethod():void
{
}
override protected function protectedMethod():void
{
}
override private function privateMethod():void
{
}
${cursor}
}
Usage:
Create new "action script file" or "new class",
remove all file content
type myclass and choose from auto-complete options template myclass
If you are actually extending MyClass, all of MyClass's functions are already available to your descendants. You can also override either of them with old header and desired new body, and still be able to call older versions of those functions via super qualifier. So, you add those functions to MyClass and let them be.
Another way is to make an interface - it's a set of declarations without any function bodies, which you have to implement in any class that wants this interface in its content. A short introduction to interfaces. Then your MyClass will be an interface, with 3 function declarations in it, and whichever class will be declared as implements MyClass will have to provide bodies for these functions.
Check other keywords on that page, including extends and implements.
Hope this helps.
EDIT: There are no abstract classes in AS3, however you can emulate abstract functions in a normal class via exception throwing:
protected function abstractFunction(...params):void {
throw new Error("Abstract!");
}
I have created a MEF plugin control that I import into my app. Now, I want the plugin to be able to import parts from the app. I can't figure how setup the catalog in the plugin, so that it can find the exports from the app. Can somebody tell me how this is done? Below is my code which doesn't work when I try to create an AssemblyCatalog with the current executing assembly.
[Export(typeof(IPluginControl))]
public partial class MyPluginControl : UserControl, IPluginControl
[Import]
public string Message { get; set; }
public MyPluginControl()
{
InitializeComponent();
Initialize();
}
private void Initialize()
{
AggregateCatalog catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
CompositionContainer container = new CompositionContainer(catalog);
try
{
container.ComposeParts(this);
}
catch (CompositionException ex)
{
Console.WriteLine(ex.ToString());
}
}
}
You don't need to do this.
Just make sure that the catalog you're using when you import this plugin includes the main application's assembly.
When MEF constructs your type in order to export it (to fulfill the IPluginControl import elsewhere), it'll already compose this part for you - and at that point, will import the "Message" string (though, you most likely should assign a name to that "message", or a custom type of some sort - otherwise, it'll just import a string, and you can only use a single "string" export anywhere in your application).
When MEF composes parts, it finds all types matching the specified type (in this case IPluginControl), instantiates a single object, fills any [Import] requirements for that object (which is why you don't need to compose this in your constructor), then assigns it to any objects importing the type.