JRuby class & Java baseclass: making private java methods available to child - jruby

I have a JRuby child class with a Java parent class. I need to override the Java function so that when it is called my JRuby method implementation is called first. The problem is that the java method is private. Any ideas?*
// Java:
public class JavaClass {
private void check(String what) {
System.out.println(what);
}
}
# JRuby:
class RubyClass < JavaClass
def check() # => private above. any way to force it public
super("RubyClass.check was called first")
end
end
*I am aware that this is not generally a good idea. I'm trying to get FXMLLoader to work in JRuby without wholesale reimplementation.

you can call the private method (using Java's reflection) ... but you won't be able to make it public on the original Java class (just on the JRuby side) and thus you can not call it using super ... here's a sample :
>> big_int = Java::JavaMath::BigInteger.new '42'
=> #<Java::JavaMath::BigInteger:0x787faefa>
>> big_int.signInt
NoMethodError: undefined method `signInt' for #<Java::JavaMath::BigInteger:0x787faefa>
from (irb):6:in `evaluate'
now let's do some Java reflection to invoke the (Java) private signInt method :
class Java::JavaMath::BigInteger
def sign_int
signInt = java_class.declared_method :signInt
signInt.accessible = true
signInt.invoke(self)
end
end
and try again :
>> big_int.sign_int
=> 0

Related

How to access protected method of Java jar file's class

I am using a Java command-line application (which is open-source) as a jar file for my jrubyonrails project. The main application is like following
public class Decoder extends Annotator {
public Decoder() {
super();
}
public static void main(String[] args) {
... // Do something that I don't want
myDesiredMethod();
... // And some other thing
}
...
}
There are many steps which I want to skip, I only want myDesiredMethod function. And it is a protected method from the parent Annotator class.
public class Annotator extends Helper {
...
protected SomeClass myDesiredMethod(boolean reMap) throws Exception { ... }
...
}
Annotator class does not have any public constructor so that I cannot:
ann = Annotator.new
It raises this error: TypeError: no public constructors for Annotator.
Then I try to implement another class which inherits Annotator in order to access myDesiredMethod. This is the jruby code I have tried so far
require 'java'
require 'decoder.jar'
java_import java.util.ArrayList
java_import java.lang.StringBuilder
module MyModule
class RuDecoder < Annotator
include_package 'com.decoder'
def self.my_method
myDesiredMethod
end
end
It returns the error: NoMethodError: undefined method 'myDesiredMethod' for MyModule::RuDecoder:Class. Seems jruby does not look for the method of the parent class.
Is there any solution in my case, I don't want to rebuild the java library to jar and manually put it into my program every time it has an update.
Turns out that I made thing over-complicated. I can call the default constructor of Annotator as following:
constructors = Annotator.java_class.declared_constructors.first
constructors.accessible = true
annotator = constructors.new_instance.to_java
And use simple call myDesiredMethod: annotator.myDesiredMethod

Any alternative to injecting Castle Windsor typed factories?

Most of my components are registered using the code-based (fluent) approach, but there is one particular component that I need to resolve differently at runtime. This is the interface and a couple of concrete implementations:-
public interface ICommsService ...
public class SerialCommsService : ICommsService ...
public class TcpCommsService : ICommsService ...
Some of our users will need the serial service while others will need the TCP service. My current solution (which works btw) is to use a typed factory and a custom component selector - the latter reads an app.config setting to determine which implementation the typed factory will resolve and return.
First the typed factory (nothing special about this):-
public interface ICommsServiceFactory
{
ICommsService Create();
void Release(ICommsService component);
}
Next, the custom component selector, which reads the fully-qualified type name from app.config (e.g. "MyApp.SomeNamespace.TcpCommsService"):-
public class CommsFactoryComponentSelector : DefaultTypedFactoryComponentSelector
{
protected override string GetComponentName(MethodInfo method, object[] arguments)
{
return ConfigurationManager.AppSettings["commsServiceType"];
}
}
Then the registration stuff:-
var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<ITypedFactoryComponentSelector>()
.ImplementedBy<CommsFactoryComponentSelector>());
container.Register(Component.For<ICommsFactory>()
.AsFactory(o => o.SelectedWith<CommsFactoryComponentSelector>()));
container.Register(Component.For<ICommsService>()
.ImplementedBy<SerialCommsService>().LifeStyle.Singleton);
container.Register(Component.For<ICommsService>()
.ImplementedBy<TcpCommsService>().LifeStyle.Singleton);
Finally, an example class with a dependency on ICommsService:-
public class Test
{
public Test(ICommsFactory commsFactory)
{
var commsService = commsFactory.Create();
...
}
}
As already mentioned, the above solution does work, but I don't like having to inject the factory. It would be more intuitive if I could just inject an ICommsService, and let something somewhere figure out which implementation to resolve and inject - similar to what I'm doing now but earlier in Windsor's "resolving pipeline". Is something like that possible?
You can use UsingFactoryMethod here:
container.Register(Component.For<ICommsService>().UsingFactoryMethod(kernel => kernel.Resolve<ICommsServiceFactory>().Create()));
You can inject ICommsService to any class now. ICommsServiceFactory can be a simple interface now:
interface ICommsServiceFactory
{
ICommsService Create();
}

Accessing non public Method of Object in JUNIT

Hi I am new to unit testing. Is it possible to access methods that are private?
A very simple example
ObjectA
----------
File file;
private void setupFile (){
//do something
file = "C:\file.dat"
}
In TestCase
File sth = ObjectA.setupFile();
assertNotNull(sth);
I am unable to test whether the file variable is null in method ObjectA.setup()
as I cannot run ObjectA.setupFile()
I am not sure about whether doing like this make sense in terms of unit testing.
So is that a better practice to write every method returning sth and set them public for easier unit testing?
Thanks in advance
In general, you should avoid changing the access of a method/field to enable testing. If you do this then you risk developers using the method directly.
However, if you do need to, then making it protected as Deco says is a good way, so it's accessible from the JUnit tests. If you do this, make sure that it is well documented that this is an method for internal use.
A better way is to test the behaviour of the public methods; you shouldn't care about internal implementation details of a class, so you should only be testing public methods. It's hard to tell from your code, but presumably, the setupFile() has effects later on other methods, so you can test those effects, not the fact that file is not null.
External dependencies (such as dependencies on file system, environment variables) can be worked around in your tests, or injected directly into the class. For the general principle, see my answer to How to test code dependent on environment variables using JUnit?
If it is not absolutely necessary to have the method as private, you can have it as package private (i.e. default access) so that you can call it directly in a JUnit test.
Package private methods can only be used in the package that they are declared, and do not become part of the API of the class. You declare a method package private by putting no modifier on it's declaration.
Here's an example to demonstrate:
public class MyClass() {
int foo;
public MyClass() {
this.foo = 0;
}
void notSoComplexCalculationMethod(int a) {
foo = a * 2;
}
//Other methods here . . .
}
public class MyClassTest extends TestCase {
private MyClass myClass;
protected void setUp() {
super.setUp();
myClass = new MyClass();
}
public void testNotSoComplexCalculationMethod() {
int a = 2;
assertEquals(4, myClass.notSoComplexCalculationMethod(a));
//Unit test passes, yay! Now you've tested a package private method.
}
}

Is there a way to specify Doctrine2 Entitymanager implementation class in Symfony2?

I'm currently working with Symfony2 and Doctrine2, but I must override the Doctrine2 EntityManager and add it some "undelete" features (ACLs inside).
So I'm wondering : is there a way to override the EntityManager class and specify Doctrine2 in Symfony2 to use it as implementation of the EntityManager?
Thank you for any help!
After Doctrine 2.4 (Doctrine 2.4 release) you need to use decorator for this. Do not extend EntityManager directly.
First you need to implement you own entity manager decorator that extends Doctrine\ORM\Decorator\EntityManagerDecorator (like #Dana)
But you can't just change doctrine.orm.entity_manager.class to your new decorator because EntityManagerDecorator requires EntityManagerInterface in it's constructor:
public function __construct(EntityManagerInterface $wrapped)
You can't just pass doctrine.orm.entity_manager as a parameter here because it will be a recursion.
And don't do like this:
return new self(\Doctrine\ORM\EntityManager::create(
What you need is to configure your decorator in services like a decorator:
yourcompany_entity_manager:
public: false
class: YourCompany\ORM\EntityManagerDecorator
decorates: doctrine.orm.default_entity_manager
arguments: ["#yourcompany_entity_manager.inner"]
Now you'll have your decorator as a default entity manager for Doctrine. #yourcompany_entity_manager.inner is actually a link to doctrine.orm.default_entity_manager that will be passed to yourcompany_entity_manager constructor.
Symfony docs for configuring decorators: link
Btw this command is very useful to debug your services:
app/console container:debug | grep entity_manager
Yes, it's possible with two steps:
1 - Override the doctrine.orm.entity_manager.class parameter to point to your custom entity manager (which should extend Doctrine\ORM\EntityManager.)
2 - Your custom entity manager must override the create method so that it returns an instance of your class. See my example below, and note the last line regarding MyEntityManager:
public static function create($conn, Configuration $config, EventManager $eventManager = null) {
if (!$config->getMetadataDriverImpl()) {
throw ORMException::missingMappingDriverImpl();
}
if (is_array($conn)) {
$conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, ($eventManager ? : new EventManager()));
} else if ($conn instanceof Connection) {
if ($eventManager !== null && $conn->getEventManager() !== $eventManager) {
throw ORMException::mismatchedEventManager();
}
} else {
throw new \InvalidArgumentException("Invalid argument: " . $conn);
}
// This is where you return an instance of your custom class!
return new MyEntityManager($conn, $config, $conn->getEventManager());
}
You'll also need to use the following in your class:
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\ORMException;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Connection;
To be honest, I'm surprised that the 2nd step is required at all, I would think this should be possible to accomplish using only the service container.
At least in Doctrine/ORM 2.4, the doc string of the EntityManager class explicitly discourages inheriting from Doctrine\ORM\EntityManager, instead they suggest inheriting from Doctrine\ORM\Decorator\EntityManagerDecorator:
/**
* The EntityManager is the central access point to ORM functionality.
* ...
* You should never attempt to inherit from the EntityManager: Inheritance
* is not a valid extension point for the EntityManager. Instead you
* should take a look at the {#see \Doctrine\ORM\Decorator\EntityManagerDecorator}
* and wrap your entity manager in a decorator.
* ...
*/
/* final */class EntityManager implements EntityManagerInterface
{
...
So, extend EntityManagerDecorator and make whatever changes you need. You will need to implement the create() factory method, but you don't need to copy EntityManager's implementation now:
use Doctrine\ORM\Decorator\EntityManagerDecorator;
use Doctrine\Common\EventManager;
use Doctrine\ORM\Configuration;
class MyEntityManager extends EntityManagerDecorator
{
/**
* {#inheritDoc}
*/
public function persist($entity)
{
// do something interesting
parent::persist($entity);
}
public function create($conn, Configuration $config, EventManager $eventManager = null)
{
return new self(\Doctrine\ORM\EntityManager::create($conn, $config, $eventManager));
}
}
Then override the doctrine.orm.entity_manager.class parameter to point to your custom entity manager class.
The docs don't cover everything, in many cases you just have to read the code.
I found the process of extending the entity manager extremely counterintuitive,
despite a decent grasp of concepts including dependency injection, service locator, code generation, caching and the decorator pattern.
Hopefully this concise example will paint a clear picture for you (this expands on the answer by #user2563451)
Symfony Version (Mon Aug 20 13:05:58 CEST 2018)
$ composer info | grep -E -e symfony/framework -e 'doctrine/(common|orm|dbal)'
doctrine/common v2.9.0 Common Library for Doctrine projects
doctrine/dbal v2.8.0 Database Abstraction Layer
doctrine/orm v2.6.2 Object-Relational-Mapper for PHP
symfony/framework-bundle v4.1.3 Symfony FrameworkBundle
config/services.yaml
App\Doctrine\ORM\CustomEntityManager:
public: false # optional afaik
decorates: doctrine.orm.original_entity_manager
arguments: [ '#App\Doctrine\ORM\CustomEntityManager.inner' ]
config/packages/doctrine.yaml
doctrine:
orm:
auto_generate_proxy_classes: '%kernel.debug%'
default_entity_manager: original
entity_managers:
original:
connection: from_env
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: false
mappings:
TimeTracking:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/php/Model'
prefix: TimeTracking\Model
alias: TimeTracking
mapping: true
#mapper_number_5:
# (...)
src/php/App/Doctrine/ORM/CustomEntityManager.php
<?php
namespace App\Doctrine\ORM;
use App\Doctrine\ORM\Proxy\SoggyProxyFactory;
use Doctrine\ORM\Decorator\EntityManagerDecorator;
use Doctrine\ORM\Proxy\ProxyFactory;
/**
* Writes custom proxy-class methods with support for the set-or-get-trait
* #property ProxyFactory soggyProxyFactory
*/
class CustomEntityManager extends EntityManagerDecorator
{
/// SUPER: __construct(EntityManagerInterface $wrapped) { $this->wrapped = $wrapped; }
private $soggyProxyFactory;
public function getProxyFactory() {
$config = $this->getConfiguration();
if (null === $this->soggyProxyFactory) {
$this->soggyProxyFactory = new SoggyProxyFactory(
$this,
$config->getProxyDir(),
$config->getProxyNamespace(),
$config->getAutoGenerateProxyClasses()
);
}
return $this->soggyProxyFactory;
}
}
references
http://symfony.com/doc/current/service_container/service_decoration.html
https://symfony.com/doc/current/doctrine/multiple_entity_managers.html

JRuby field_accessor final member

I have a java field that I want to subclass in jruby defined like so:
public abstract class FilterObjectStream<S, T> implements ObjectStream<T> {
protected final ObjectStream<S> samples;
I then want to subclass this class and access this member, I have tried to access the protected final member like this, using field_accessor:
class NameSampleDataStream
field_accessor :samples
end
class HtmlNameSampleDataStream < NameSampleDataStream
def read
token = self.samples.read()
token
end
end
I am getting an error message:
SecurityError: Cannot change final
field 'samples'
I guess the exception answers the question but is there anyway that I can access this variable or is the game up?
I cannot change the java source unfortunately.
Can you try just doing "field_reader"? It's possible to set a final field accessible, but we don't do that for you, and what you want here is just a reader, right?