I'm writing a cordapp where I need to use state classes that require a custom serializer. I have got one defined according to the documentation, but it does not seem to be picked up when I'm trying to run contract tests via corda-node-driver (exactly as per corda-helloworld template).
Here is the class definition (suitably obfuscated):
public class BlahBlahSerializer implements SerializationCustomSerializer<BlahBlah, BlahBlahProxy> {
public IOUState fromProxy(BlahBlahProxy proxy) {
/* impl */
}
public BlahBlahProxy toProxy(BlahBlah state) {
/* impl */
}
}
}
The .class file for the above is in the cordap jar created by the driver, and so are the BlahBlahProxy.class, contract and state classes. All these classes are is in the same package as the state and contract classes themselves.
I have enabled DEBUG logging for corda and I can see a lot of lines like this one
[Test worker] CachingCustomSerializerRegistry - action="Using custom serializer", class=java.security.PublicKey, declaredType=java.security.PublicKey
but there isn't a line for my class.
I wonder if there is anything else I need to do to enable custom serializer to be picked up?
I think #fowlerr is relatively correct may have been an issue with this in the past.
Take a look at the latest version of Corda (4.5) and see if you can get a custom serializer work there. Hopefully, you won't have issues with something like this :
/**
* The class lacks a public constructor that takes parameters it can associate
* with its properties and is thus not serializable by the CORDA serialization
* framework.
*/
class Example {
private int a;
private int b;
public int getA() { return a; }
public int getB() { return b; }
public Example(List<int> l) {
this.a = l.get(0);
this.b = l.get(1);
}
}
/**
* This is the class that will Proxy instances of Example within the serializer
*/
public class ExampleProxy {
/**
* These properties will be serialized into the byte stream, this is where we choose how to
* represent instances of the object we're proxying. In this example, which is somewhat
* contrived, this choice is obvious. In your own classes / 3rd party libraries, however, this
* may require more thought.
*/
private int proxiedA;
private int proxiedB;
/**
* The proxy class itself must be serializable by the framework, it must thus have a constructor that
* can be mapped to the properties of the class via getter methods.
*/
public int getProxiedA() { return proxiedA; }
public int getProxiedB() { return proxiedB; }
public ExampleProxy(int proxiedA, int proxiedB) {
this.proxiedA = proxiedA;
this.proxiedB = proxiedB;
}
}
/**
* Finally this is the custom serializer that will automatically loaded into the serialization
* framework when the CorDapp Jar is scanned at runtime.
*/
public class ExampleSerializer implements SerializationCustomSerializer<Example, ExampleProxy> {
/**
* Given an instance of the Example class, create an instance of the proxying object ExampleProxy.
*
* Essentially convert Example -> ExampleProxy
*/
public ExampleProxy toProxy(Example obj) {
return new ExampleProxy(obj.getA(), obj.getB());
}
/**
* Conversely, given an instance of the proxy object, revert that back to an instance of the
* type being proxied.
*
* Essentially convert ExampleProxy -> Example
*/
public Example fromProxy(ExampleProxy proxy) {
List<int> l = new ArrayList<int>(2);
l.add(proxy.getProxiedA());
l.add(proxy.getProxiedB());
return new Example(l);
}
}
source from docs: https://docs.corda.net/docs/corda-os/4.4/cordapp-custom-serializers.html#writing-a-custom-serializer
Related
For configuration I use simple xml. I also use this model for TableView. My problem is using of boolean. TableView needs BooleanProperty but simple xml cannot access to this object, obviously. How can I combine this without write big code?
Model
#Root(name="scriptdata")
#Order(elements={"title", "active"})
public class ScriptData {
#Element (required=true)
private String title;
#Element (required=false)
private BooleanProperty active;
/**
*
* #param title
* #param active
*/
public ScriptData() {
this.active = new SimpleBooleanProperty(active);
}
public boolean isActive() {
return active.getValue();
}
public void setActive(boolean active) {
this.active.set(active);
}
CellFactory
modulActiveColumn.setCellValueFactory(new PropertyValueFactory<>("active"));
modulActiveColumn.setCellFactory(CheckBoxTableCell.forTableColumn(modulActiveColumn));
modulActiveColumn.setOnEditCommit((EventHandler<CellEditEvent>) t -> {
((ScriptData) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setActive((boolean) t.getNewValue());
}
My problem is using of boolean. TableView needs BooleanProperty
You're wrong. In fact the TableView never gains access to the BooleanProperty object stored in the active field of it's items.
PropertyValueFactory uses reflection to
Access a property object by invoking a method with the constructor parameter concatenated with "Property". (This method would be called activeProperty() in your case).
If the above doesn't work it wraps the value returned by a the getter for the property in a ObservableValue. (The name of the getter in this case is getActive() or isActive).
In your case the cellValueFactory does something similar to the following factory
modulActiveColumn.setCellValueFactory(cellData -> new SimpleBooleanProperty(cellData.getValue().isActive()));
Using a boolean field to store the data achieves exactly the same result in your case. The drawback of this approach is that programatic updates of the property do not trigger an update of the TableView and the edits need to be handled manually.
#Root(name="scriptdata")
#Order(elements={"title", "active"})
public class ScriptData {
#Element (required=true)
private String title;
#Element (required=false)
private boolean active;
/**
*
* #param title
* #param active
*/
public ScriptData() {
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
}
I have an entity BlogPost with a status property. This status property depends on an external API call which is handled via the doctrine postLoad event. All other properties are stored in the local database.
public function postLoad(BlogPost $post)
{
$this->postHandler->calculateStatus($post);
}
The problem is, in some cases i don't want to calculate the status at all. For example if i want to get only the description of all blogposts.
With the code above, all blog entities being loaded will trigger the postLoad event even if i just want to have values from a local database. That is very expensive and not acceptable.
So for example in my repository class i want to get all BlogPosts having a website without invoking the postLoad event.
public function findBlogPosts()
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('bp')
->from('AppBundle:BlogPosts', 'bp')
->innerJoin('bp.website', 'w');
return $qb->getQuery()->getResult();
}
Is there a way to say "Yes, load the BlogPost collection, but do not fire event!" ???
Any other approaches? Custom event?
Thanks
Why don't just move this logic outside the post entity and event listener? If you know when you need to calculate the status you can do it explicitly.
For example
$post = $this->entityManager->find(BlogPost::class, $postId);
$status = $this->postHandler->calculateStatus($post);
The other approach I could suggest is not good but works. You could use lazy calculation and instead of calling $this->postHandler->calculateStatus($this) in postLoad event listener you could inject postHandler service into entity and perform the calculation in the moment you actually need it.
For example if you need calculation when calling $blogPost->getStatus() method, you could do it this way:
interface PostHandlerAwareInterface
{
public function setPostHandler(PostHandlerInterface $postHandler): void;
}
class EntityServiceInjectorEventSubscriber implements EventSubscriber
{
/** #var PostHandlerInterface */
private $postHandler;
public function postLoad($entity): void
{
$this->injectServices($entity);
}
public function postPersist($entity): void
{
$this->injectServices($entity);
}
private function injectServices($entity): void
{
if ($entity instanceof PostHandlerAwareInterface) {
$entity->setPostHandler($this->postHandler);
}
}
}
class BlogPost extends PostHandlerAwareInterface
{
/** #var PostHandlerInterface */
private $postHandler;
private $status;
public function setPostHandler(PostHandlerInterface $postHandler): void
{
$this->postHandler = $postHandler;
}
public function getStatus()
{
if (null === $this->status) {
$this->postHandler->calculateStatus($this);
}
return $this->status;
}
}
If you don't like this idea you still could manage it via (BUT I STRONGLY DO NOT RECOMMEND DO THIS DIRTY HACK) setting the flag to your entity event listener.
You could inject your entity event listener to the code and set flag before fetching data:
class BlogPostCalculateStatusListener
{
/** #var bool */
private $calculationEnabled = true;
public function suspendCalculation(): void
{
$this->calculationEnabled = false;
}
public function resumeCalculation(): void
{
$this->calculationEnabled = true;
}
public function postLoad(BlogPost $post): void
{
if ($this->calculationEnabled) {
$this->postHandler->calculateStatus($post);
}
}
}
$this->calculateStatusListener->suspendCalculation();
$blogPosts = $blogPostRepository->findBlogPosts();
$this->calculateStatusListener->resumeCalculation();
Hope this helps.
PS. If you want to get only the descriptions of all blog posts you can do this way:
class BlogPostRepository
{
public function findBlogPosts()
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('bp.description')
->from('AppBundle:BlogPosts', 'bp')
->innerJoin('bp.website', 'w');
return $qb->getQuery()->getArrayResult();
}
}
getArrayResult does not invoke lifecycle callbacks.
Since i haven't found a real similar use case on the internet, i'll go for the following solution which seems the easiest and most acceptable cleanest to me. Maybe someone else could find this useful.
Implement a TransientLoadable Interface
interface TransientLoadable
{
public function isLoaded() : bool;
public function setLoaded(bool $loaded) : TransientLoadable;
public function setTransientLoadingFunction(\Closure $loadingFunction) :
TransientLoadable;
}
Implement the entity
class BlogPost implements TransientLoadable
{
...
}
Setup Loading function on postLoad Event
public function postLoad(BlogPost $post)
{
$func = function() use ($postHandler, $post)
{
//Since there may be another fields being loaded from the same API, catch them also since data is anyway in the same request
$postHandler->setAllDataFromAPI($post)
//Set the loading state to true to prevent calling the API again for the next property which may also be transient
$post->setLoaded(true);
}
$post->setTransientLoadingFunction($func)
}
Use the built-in lazy loading mechanism to get the property from the API only when it's needed
class BlogPost implements TransientLoadable
{
private function getStatus() : int
{
if (!$this->isLoaded) {
call_user_function($this->loadingFunction)
}
return $this->status;
}
private function getVisitorCount() : int
{
if (!$this->isLoaded) {
call_user_function($this->loadingFunction)
}
return $this->visitorCount;
}
}
So what's happening? Let's imagine we want to get the status and the visitor count, both are loaded via a single external API call.
If some api-dependent property of the entity is needed, all other properties gets loaded too (since we don't want to have for each property another call). This in ensured through the loaded function of the TransientLoadable interface. All data gets loaded by the setAllDataFromAPI function which is injected as a closure function.
I think that is not the cleanest solution. The loading stuf should be done by an extra layer on top of the entity class. Since sonata admin does not deal with such an layer, i think that this solution is cleaner than writing the loading mechanism directly to the entity class.
I am open to another suggestions or feedback
Thanks
Symfony 2.8.13 / Doctrine ORM 2.5.5 / PHPUnit 5.7.5
I want to test a method of a class that makes use of the doctrine entity manager. This public method calls a private one that instantiates a Bookmark entity, flushes it and returns this entity. Then later, in the tested method I need to access the entity Id. Everything is mocked excepted the Bookmark entity itself. The main problem is that there is no setId() method in my entity. Here is the code and my main idea to solve this issue but I don't know if it is correct ?
Tested class and method
class BookmarkManager
{
//...
public function __construct(TokenStorageInterface $tokenStorage, ObjectManager $em, Session $session)
{
//...
}
public function manage($bookmarkAction, $bookmarkId, $bookmarkEntity, $bookmarkEntityId)
{
//...
$bookmark = $this->add($bookmarkEntity, $bookmarkEntityId);
//...
$bookmarkId = $bookmark->getId();
//...
}
private function add($entity, $entityId)
{
//...
$bookmark = new Bookmark();
//...
$this->em->persist($bookmark);
$this->em->flush();
return $bookmark;
}
}
Test
class BookmarkManagerTest extends \PHPUnit_Framework_TestCase
{
public function testThatRestaurantAdditionToBookmarksIsWellManaged()
{
//...
// THIS WON'T WORK AS NO setId() METHOD EXISTS
$entityManagerMock->expects($this->once())
->method('persist')
->will($this->returnCallback(function ($bookmark) {
if ($bookmark instanceof Bookmark) {
$bookmark->setId(1);
}
}));
//...
$bookManager = new BookmarkManager($tokenStorageMock, $entityManagerMock, $sessionMock);
//...
}
}
Solutions ?
1- Make usage of reflection class as proposed here :
$entityManagerMock->expects($this->once())
->method('persist')
->will($this->returnCallback(function ($bookmark) {
if ($bookmark instanceof Bookmark) {
$class = new \ReflectionClass($bookmark);
$property = $class->getProperty('id');
$property->setAccessible(true);
$property->setValue($bookmark, 1);
//$bookmark->setId(1);
}
}));
2- Create a test Boookmark entity that extends from the real one and add a setId() method. Then create a mock of this class and replace and customize the one got from the ReturnCallback method with this one ? It seems crappy...
Any thoughts ? Thanks for your help.
The reflection looks interesting but it decreases readability of tests (mixing with mocks makes the situation tough).
I would create a fake for entity manager and implements there setting id based on reflection:
class MyEntityManager implements ObjectManager
{
private $primaryIdForPersitingObject;
public function __construct($primaryIdForPersitingObject)
{
$this->primaryIdForPersitingObject = $primaryIdForPersitingObject;
}
...
public function persist($object)
{
$reflectionClass = new ReflectionClass(get_class($object));
$idProperty = $reflectionClass->getProperty('id');
$idProperty->setAccessible(true);
$idProperty->setValue($object, $this->primaryIdForPersitingObject);
}
public function flush() { }
...
}
Once you implemented this, you can inject the instance of MyEntityManager and make your tests small and easier to maintain.
You test would look like
<?php
class BookmarkManagerTest extends \PHPUnit_Framework_TestCase
{
public function testThatRestaurantAdditionToBookmarksIsWellManaged()
{
// ...
$entityManager = MyEntityManager(1);
//...
$bookManager = new BookmarkManager($tokenStorageMock, $entityManager, $sessionMock);
//...
}
}
Of course, a situation may be harder if there is a need of setting different ids for many persisting objects. Then you can, for example, increase $primaryIdForPersitingObject on persist call
public function persist($object)
{
$reflectionClass = new ReflectionClass(get_class($object));
$idProperty = $reflectionClass->getProperty('id');
$idProperty->setAccessible(true);
$idProperty->setValue($object, $this->primaryIdForPersitingObject);
$this->primaryIdForPersitingObject++;
}
It may be extended even further to have separate primaryIdForPersitingObject each entity class, and your tests will be still clean.
To test an API calling, I would like to test an entity lifecycle.
Get with no content
Post a content, returning an ID
Patch the content
Get with content
Delete the content
I would use the ID returned in the post method. I try with a private property in my test class but in each method test, the property is reseted. How I can to test with a dynamic variable in my test class?
An example of my code and the response from PHPUnit:
class CommentControllerTest extends PHPUnit_Framework_TestCase
{
private $commentId;
public function setUp()
{
}
public function testPostValidComment()
{
$this->commentId = 42;
}
public function testUpdateComment()
{
var_dump($this->commentId); // NULL
}
public function testDeleteComment()
{
var_dump($this->commentId); // NULL
}
}
Why my var_dump($this->commentId); returns NULL?
Use the #depends annotation for establishing the execution order and passing the value from one test to the next:
class CommentControllerTest extends PHPUnit_Framework_TestCase
{
public function testPostValidComment()
{
$commentId = 42;
return $commentId;
}
/**
* #depends testPostValidComment
*/
public function testUpdateComment($commentId)
{
return $commentId;
}
/**
* #depends testUpdateComment
*/
public function testDeleteComment($commentId)
{
}
}
Note:
if a test fails, other tests that depends on it will not run. So with the example setup:
test POST -> test UPDATE -> test DELETE
if the UPDATE fails you won't know if the DELETE works or not.
To solve this you can change the depends chain to be like this:
test POST -> test UPDATE
test POST -> test DELETE
So if the UPDATE fails, the DELETE will be tested. In this case, the POST test will be executed twice, once for the UPDATE and again for the DELETE.
PHPUnit docs on dependencies.
A have a new feature that forces me to pass some new data structure to my EJBs.
This is a user session context that has some information about the current user.
How can I pass this data to my EJBs without refactoring my method signature and calls?
Use ThreadLocal? But if it is not on the same JVM?
There's some code bellow. Can you have a tip to me?
/** created at login time, when user put it's credential */
public class UserSessionContext {
private User current;
private Company company;
// getters e setters
}
/** web page controller */
#ManagedBean // at web tier
public class ListCustomersController {
#EJB
CustomersRepository customers; // some remote interface
// getters / setters
private List<Filters> filters; // from the UI
/** used in a datatable component */
public List<Customer> getAll(){
return customers.getAllWith(filters); // I have no UserSessionContext parameter
}
}
/** used by web controller */
#Stateless
public CustomersEJB implements CustomersRepository {
#Inject
UserSessionContext currentContext; // injected before call this object
public List<Customer> getAllWith(List<Filter> filters){
TypeQuery<Customer> customersQuery = ... //
customersQuery.setParameter("company",currentContext.getCompany());
return customersQuery.getResultList();
}
}
There is no standard mechanism for doing this (JSR-149). WebSphere Application Server has a Work Area Service programming model extension that can be used to propagate contexts in this manner.