You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@isis.apache.org by Kevin Meyer <ke...@kmz.co.za> on 2011/03/17 10:20:44 UTC

How do I directly create/initialise an ObjectAdapter?

Dan, Rob?

In the SQL object store AbstractJdbcFieldMapping, the method
"public void initializeField(ObjectAdapter object, Results rs)"
explicitly converts the record set field into a string, then uses
"field.getSpecification().getFacet(EncodableFacet.class).fromEncodedString(valueString)"
to create an object adapter from the string.

This is quite messy and obviously will kill anything like a BLOB (e.g. an
image!)

How do I directly create (for example) an ObjectAdapter containing an Isis
applib Date value, to pass on to
"((OneToOneAssociation) field).initAssociation(object, restoredValue);"

I guess the real requirement is creating the ObjectAdapter (for the
retrieved value object) to pass on to "initAssociation".

The same would go for the other values (e.g. Image), and extend to custom
written value types (ValueSemanticsProvider? but I see that being handled
by an AbstractJdbcFieldMapping class implementation).

In short - I am trying to move away from fetching/storing properties as
strings. This started with recoding the Sql object store to use prepared
statements with inserted objects (e.g. WHERE value = ?) instead of (WHERE
value = 'zorkmid').

Regards,
Kevin



Re: How do I directly create/initialise an ObjectAdapter?

Posted by Dan Haywood <dk...@gmail.com>.
On 17/03/2011 18:47, Kevin Meyer - KMZ wrote:
>>> In the SQL object store AbstractJdbcFieldMapping, the method
>>> ...
>>> to create an object adapter from the string.
>>>
>>> This is quite messy and obviously will kill anything like a BLOB (e.g. an
>>> image!)
>> Well, not necessarily.  There's nothing to prevent your value type to
>> encode itself as a string, eg using base 64 encoding.
> Eeek! Do you hear 30% data bloat? ;)
Well, any encoding will do.  Base 64 is just easy, that's all.

We could, I suppose, extend ValueSemanticsProvider to support two 
different types of Encoders, the current 
org.apache.isis.applib.adapters.EncoderDecoder that encodes/decodes to 
Strings, and another one that encodes to byte[].  The marshalling could 
perhaps ask for the former, but fall back to the latter.

If you want to try a spike on it, go ahead.



>>> How do I directly create (for example) an ObjectAdapter containing an Isis
>>> applib Date value, to pass on to
>>> "((OneToOneAssociation) field).initAssociation(object, restoredValue);"
>>>
>>> I guess the real requirement is creating the ObjectAdapter (for the
>>> retrieved value object) to pass on to "initAssociation".
>> I'm not sure that you do need to do this if you use VSPs, but to answer
>> your question: you can use:
>>
>> IsisContext().getPersistenceSession().getAdapterManager().adapterFor(object).
> Thanks - I'll give this a try. I'm assuming that the following'll work:
>
> Date newDateValue = rs.getDate(columnName);
>
> ObjectAdapter  restoredValue =  IsisContext(). \
> 	getPersistenceSession().\
> 	getAdapterManager(). \
> 	adapterFor(newDateValue);
>
> ((OneToOneAssociation) field).initAssociation(object, restoredValue)
>
Yeah, sounds about right.

Dan


PS: as you saw a few weeks ago, I've moved all this stuff into 
runtimes.dflt (previously it was in core.runtime).  That's because I 
want to allow for other runtime implementations, that perhaps have less 
moving parts and leverage more existing stuff, eg JDO 3.0 (ISIS-14), or 
even very simple pojos that wrap maps and that are persisted as JSON in 
Mongo/Couch.  I see these alternative runtime implementations as 
supporting adapters just by new'ing up, ie new 
ObjectAdapterImpl(dataValue) ... the point would mostly be to provide 
access into the ObjectSpecification (ie metamodel).



Re: How do I directly create/initialise an ObjectAdapter?

Posted by Kevin Meyer - KMZ <ke...@kmz.co.za>.
> > In the SQL object store AbstractJdbcFieldMapping, the method
> > ...
> > to create an object adapter from the string.
> >
> > This is quite messy and obviously will kill anything like a BLOB (e.g. an
> > image!)
> Well, not necessarily.  There's nothing to prevent your value type to 
> encode itself as a string, eg using base 64 encoding.  

Eeek! Do you hear 30% data bloat? ;)

> > How do I directly create (for example) an ObjectAdapter containing an Isis
> > applib Date value, to pass on to
> > "((OneToOneAssociation) field).initAssociation(object, restoredValue);"
> >
> > I guess the real requirement is creating the ObjectAdapter (for the
> > retrieved value object) to pass on to "initAssociation".
> 
> I'm not sure that you do need to do this if you use VSPs, but to answer 
> your question: you can use:
> 
> IsisContext().getPersistenceSession().getAdapterManager().adapterFor(object).

Thanks - I'll give this a try. I'm assuming that the following'll work:

Date newDateValue = rs.getDate(columnName);

ObjectAdapter  restoredValue =  IsisContext(). \
	getPersistenceSession().\
	getAdapterManager(). \
	adapterFor(newDateValue);

((OneToOneAssociation) field).initAssociation(object, restoredValue)

> If you look at the implementation (AdapterManagerDefault) then you'll 
> see that we look for a ValueFacet on the spec of the provided object.  
> If so, we create a "standalone" adapter to wrap the value.

Something to keep in mind.


Thanks,
Kevin


Re: How do I directly create/initialise an ObjectAdapter?

Posted by Dan Haywood <dk...@gmail.com>.
On 06/04/2011 20:37, Kevin Meyer - KMZ wrote:
>
> Creating the applib value type first, then using the ...adapterFor(object)
> method made adding support multi-column SQL object store support
> real easy.
>
> I was able to add support for the applib.value.Money value type quite
> easily, by extending AbstractJdbcFieldMapping to create a
> "AbstractJdbcMultiFieldMapping" type - which stores "currency" and
> "value" in separate columns.
>
>
Good stuff, thanks for putting the time in on this!

Cheers
Dan

Re: How do I directly create/initialise an ObjectAdapter?

Posted by Kevin Meyer - KMZ <ke...@kmz.co.za>.
> > I guess the real requirement is creating the ObjectAdapter (for the
> > retrieved value object) to pass on to "initAssociation".
> 
> I'm not sure that you do need to do this if you use VSPs, but to answer 
> your question: you can use:
> 
> IsisContext().getPersistenceSession().getAdapterManager().adapterFor(object).

Thanks - I have used this method with a good degree of success, see 
below..

> 
> If you look at the implementation (AdapterManagerDefault) then you'll 
> see that we look for a ValueFacet on the spec of the provided object.  
> If so, we create a "standalone" adapter to wrap the value.
> 
> > The same would go for the other values (e.g. Image), and extend to custom
> > written value types (ValueSemanticsProvider? but I see that being handled
> > by an AbstractJdbcFieldMapping class implementation).
> I didn't write the AJFM, but as you've noted it's implementation is 
> hard-coded to only encode to strings, and it then leverages the 
> VSP#EncoderDecoder to do the heavy lifting.

Creating the applib value type first, then using the ...adapterFor(object) 
method made adding support multi-column SQL object store support 
real easy.

I was able to add support for the applib.value.Money value type quite 
easily, by extending AbstractJdbcFieldMapping to create a 
"AbstractJdbcMultiFieldMapping" type - which stores "currency" and 
"value" in separate columns.



Re: How do I directly create/initialise an ObjectAdapter?

Posted by Dan Haywood <dk...@gmail.com>.
Hi Kevin,

within...

On 17/03/2011 09:20, Kevin Meyer wrote:
> Dan, Rob?
>
> In the SQL object store AbstractJdbcFieldMapping, the method
> "public void initializeField(ObjectAdapter object, Results rs)"
> explicitly converts the record set field into a string, then uses
> "field.getSpecification().getFacet(EncodableFacet.class).fromEncodedString(valueString)"
> to create an object adapter from the string.
>
> This is quite messy and obviously will kill anything like a BLOB (e.g. an
> image!)
Well, not necessarily.  There's nothing to prevent your value type to 
encode itself as a string, eg using base 64 encoding.  What you will 
need to do is to write and register a ValueSemanticsProvider for the 
value type that you want to persist though (there are plenty of 
implementations in the codebase to look at; basically your VSP will need 
to implement getEncoderDecoder() method as a minimum).

The other thing to do is to register the VSP. If this is a custom value 
type, then you can annotate it with @Value.  Otherwise, you'll need to 
register the VSP in isis.properties; have a look at 
ValueFacetFactoryTest#testSemanticsProviderNameCanBePickedUpFromConfiguration 
for details on the syntax:

isis.core.progmodel.value.com.mycompany.myapp.MyValueSemanticProvider.semanticsProviderName=com.mycompany.myapp.MyValueSemanticProvider


> How do I directly create (for example) an ObjectAdapter containing an Isis
> applib Date value, to pass on to
> "((OneToOneAssociation) field).initAssociation(object, restoredValue);"
>
> I guess the real requirement is creating the ObjectAdapter (for the
> retrieved value object) to pass on to "initAssociation".

I'm not sure that you do need to do this if you use VSPs, but to answer 
your question: you can use:

IsisContext().getPersistenceSession().getAdapterManager().adapterFor(object).

If you look at the implementation (AdapterManagerDefault) then you'll 
see that we look for a ValueFacet on the spec of the provided object.  
If so, we create a "standalone" adapter to wrap the value.


> The same would go for the other values (e.g. Image), and extend to custom
> written value types (ValueSemanticsProvider? but I see that being handled
> by an AbstractJdbcFieldMapping class implementation).
I didn't write the AJFM, but as you've noted it's implementation is 
hard-coded to only encode to strings, and it then leverages the 
VSP#EncoderDecoder to do the heavy lifting.

If you wanted to have support to something else (eg Images to BLOBs), 
then I think we'd need to define something equivalent mechanism to allow 
values to be marshalled to other types (eg byte[]).  However, only 
objectstores are likely to need this, so I'd probably want us to 
introduce an applib scoped to each objectstore (eg sql/applib) for these 
value types.  You can see I do a similar thing for Restful viewer and 
Wicket viewer.


HTH
Dan

> In short - I am trying to move away from fetching/storing properties as
> strings. This started with recoding the Sql object store to use prepared
> statements with inserted objects (e.g. WHERE value = ?) instead of (WHERE
> value = 'zorkmid').
>
> Regards,
> Kevin
>
>
>