In my Grails app, the original date read from the database is equal to:
{ endDate=2015-10-19 19:00:00.0}
While the JSON result is:
{"endDate": "2015-10-19T16:00:00Z"}
I think this is maybe related to time zone conversion. How could I show the original date without any timezone conversions in JSON?
Depending on which time zone you're in, 2015-10-19 19:00:00.0 and 2015-10-19T16:00:00Z may not be different times, they may be just different representations of the same time (instant).
In my case, I use a custom marshaller to ensure that times in my API's JSON response always use the UTC time zone. My custom marshaller looks like this:
import org.springframework.stereotype.Component
#Component
class DateMarshaller implements CustomMarshaller {
#Override
def getSupportedTypes() {
Date
}
#Override
Closure getMarshaller() {
{ Date date ->
TimeZone tz = TimeZone.getTimeZone('UTC')
date?.format("yyyy-MM-dd'T'HH:mm:ss'Z'", tz)
}
}
}
Remember to register the package this marshaller is in for Spring bean scanning in Config.groovy. The interface it implements is:
interface CustomMarshaller {
/**
* Indicates the type(s) of object that this marshaller supports
* #return a {#link Class} or collection of {#link Class}
* if the marshaller supports multiple types
*/
def getSupportedTypes()
Closure getMarshaller()
}
Then I have a service that registers all my instances of CustomMarshaller for the relevant type(s):
import grails.converters.JSON
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
import javax.annotation.PostConstruct
class MarshallerRegistrarService implements ApplicationContextAware {
static transactional = false
ApplicationContext applicationContext
// a combination of eager bean initialization and #PostConstruct ensures that the marshallers are registered when
// the app (or a test thereof) starts
boolean lazyInit = false
#PostConstruct
void registerMarshallers() {
Map<String, CustomMarshaller> marshallerBeans = applicationContext.getBeansOfType(CustomMarshaller)
marshallerBeans.values().each { CustomMarshaller customMarshaller ->
customMarshaller.supportedTypes.each { Class supportedType ->
JSON.registerObjectMarshaller supportedType, customMarshaller.marshaller
}
}
}
}
This is a fairly involved solution, but In my case I'm using Grails 2.5.X. If I was using Grails 3.X I'd try to use JSON views instead.
If my memory is correct, JSON spec does not actually define a format for date format. But everybody uses ISO 8601, so it sort of de-facto standard. And most just always use Zulu time zone.
I searched myself some time ago, on ways to force Grails JSON to render dates in certain time zone, but failed. In my Grails web app, I just declare date fields as text and format them to proper time zone and format in my own code. On the good side, it also has an added benefit that you can guarantee it to stay that way in future. (I'm, using Grails since about 1.1 and did see breaking changes on several occasions.)
Working on an old application that is built with grails 2.3.11 in which for some unbeknownst reason #Dónal's solution wasn't working. Fortunately, I found an easier/more straightforward approach to register a custom marshaller on mrhaki's blog.
So, I made a copy of the default DateMarshaller that resides in org.codehaus.groovy.grails.web.converters.marshaller.json and modified the date formatter in my custom DateMarshaller and then registered the marshaller using the snippet below, taken from mrhaki's post.
dateMarshaller(ObjectMarshallerRegisterer) {
// Assign custom marshaller instance.
marshaller = new DateMarshaller()
// Set converter class type.
converterClass = JSON
// Optional set priority. Default value is 0.
priority = 1
}
Just make sure that your Custom Marshaller has a higher priority than the default one. Works like a charm!
Related
I'm trying to use a rest-service created in grails 2.5.5 which has a Date property as follows:
import grails.rest.*
#Resource(uri='/restDomain', readOnly=true)
class RestDomain {
Date myDate
}
But when calling from another grails app (v2.5.5 or v3.1.9) like this:
new RestBuilder().get('http://localhost:8080/restApp/restDomain.json').json.collect {
new RestDomain(it)
}
I get a Cannot cast object '2016-01-20T12:36:57Z' with class 'java.lang.String' to class 'java.util.Date' error.
I've already added this in application.yml (grails v3.1.9) at the very bottom of the file
---
grails:
databinding:
dateFormats:
- yyyy-MM-dd'T'HH:mm:ssX
- yyyy-MM-dd'T'HH:mm:ss.SSSX
and this in Config.groovy (grails v2.5.5)
grails.databinding.dateFormats = ["yyyy-MM-dd'T'HH:mm:ssX", "yyyy-MM-dd'T'HH:mm:ss.SSSX"]
but doesn't seem to work at all
Note: In both client apps I have the corresponding src/groovy/restApp/RestDomain.groovy class as follows:
package restApp
class RestDomain {
Date myDate
}
Note 2: The grails 3.1.9 client app has compile 'org.grails:grails-datastore-rest-client:6.0.0.M1' dependency the in build.gradle dependencies section, and the grails 2.5.5 client app has compile ':rest-client-builder:2.1.1' in the BuildConfig.groovy plugins section
Any help getting it to work in a Grails 2.5.x or Grails 3.1.x app would be really appreciated
The 'Z' at the end of your date string signifies that the time zone is UTC which is not a valid ISO 8601 time zone specification that you could parse with the 'X' in your time formats. It is a literal that should be parseable with
yyyy-MM-dd'T'HH:mm:ss'Z'
Adding an answer to provide a workaround on how I resolved this, but I will not mark it as the accepted answer because it is not the ideal way to solved it, so here it is:
Added this in my client controller (I guess that the bindData method is the key here):
new RestBuilder().get('http://localhost:8080/restApp/restDomain.json').json.collect {
def restDomainInstance = new RestDomain()
bindData(restDomainInstance, it)
restDomainInstance
}
and changed RestDomain.groovy to this
package restApp
import java.text.SimpleDateFormat
import org.grails.databinding.BindUsing
class RestDomain {
#BindUsing({ obj, source ->
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX")
.parse(source.getPropertyValue('myDate'))
})
Date myDate
}
The X in the SimpleDateFormat is for recognizing the timezone as UTC, so the jvm converts it to its current timezone later (in my case: -04:00 GMT)
I'm really stuck with cast Rabbit response to POJO. How to do it properly? On sprin.io just no practical example.
So I'm trying to do it with this
#Bean
public DefaultClassMapper typeMapper() {
DefaultClassMapper typeMapper = new DefaultClassMapper();
Map<String, Class> idClassMapping = new HashMap<String, Class>();
idClassMapping.put("range", Loan.class);
typeMapper.setIdClassMapping(idClassMapping);
//typeMapper.setDefaultType(Loan.class);
return typeMapper;
}
#Bean
public MessageConverter messageConverter(DefaultClassMapper defaultClassMapper){
JsonMessageConverter jsonMessageConverter = new JsonMessageConverter();
jsonMessageConverter.setClassMapper(defaultClassMapper);
return jsonMessageConverter;
}
"range" actually fake value from example. Also this really doesn't work type problemn on .setIdClassMapping() . Also I can't use default mapper because serve send header without type hinting field. And I have no control on this remote server. Data format always JSON.
Caused by: org.springframework.amqp.support.converter.MessageConversionException: failed to convert Message content. Could not resolve __TypeId__ in header
Any suggestions working example for marshalling/demarshalling Java objects. I have completely different class for send back value from my code. I'm using java 8.
Just write your own ClassMapper - don't use the default one if your decision criteria to choose the class type is not compatible with its internals.
Or, you can subclass the DefaultClassMapper and override getClassIdFieldName() to tell it which message property to use.
I am using Java EE 6 and need to load configuration from a ".properties" file. Is there a recommended way (best practice) to load the values from the configuration file using dependency injection? I found annotations for this in Spring, but I have not found a "standard" annotation for Java EE.
This guy have developed a solution from scratch:
http://weblogs.java.net/blog/jjviana/archive/2010/05/18/applicaction-configuration-java-ee-6-using-cdi-simple-example
"I couldn't find a simple example of how to configure your application
with CDI by reading configuration attributes from a file..."
But I wonder if there is a more standard way instead of creating a configuration factory...
Configuration annotation
package com.ubiteck.cdi;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.enterprise.util.Nonbinding;
import javax.inject.Qualifier;
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
public #interface InjectedConfiguration {
/**
* Bundle key
* #return a valid bundle key or ""
*/
#Nonbinding String key() default "";
/**
* Is it a mandatory property
* #return true if mandator
*/
#Nonbinding boolean mandatory() default false;
/**
* Default value if not provided
* #return default value or ""
*/
#Nonbinding String defaultValue() default "";
}
The configuration factory could look like :
import java.text.MessageFormat;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
public class ConfigurationInjectionManager {
static final String INVALID_KEY="Invalid key '{0}'";
static final String MANDATORY_PARAM_MISSING = "No definition found for a mandatory configuration parameter : '{0}'";
private final String BUNDLE_FILE_NAME = "configuration";
private final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_FILE_NAME);
#Produces
#InjectedConfiguration
public String injectConfiguration(InjectionPoint ip) throws IllegalStateException {
InjectedConfiguration param = ip.getAnnotated().getAnnotation(InjectedConfiguration.class);
if (param.key() == null || param.key().length() == 0) {
return param.defaultValue();
}
String value;
try {
value = bundle.getString(param.key());
if (value == null || value.trim().length() == 0) {
if (param.mandatory())
throw new IllegalStateException(MessageFormat.format(MANDATORY_PARAM_MISSING, new Object[]{param.key()}));
else
return param.defaultValue();
}
return value;
} catch (MissingResourceException e) {
if (param.mandatory()) throw new IllegalStateException(MessageFormat.format(MANDATORY_PARAM_MISSING, new Object[]{param.key()}));
return MessageFormat.format(INVALID_KEY, new Object[]{param.key()});
}
}
Tutorial with explanation and Arquillian test
Even though it does not exactly cover your question, this part of the Weld documentation might be of interest for you.
Having mentioned this - no, there is no standard way to inject arbitrary resources / resource files. I guess it's simply beyond the scope of a spec to standardise such highly custom-dependent requirement (Spring is no specification, they can simply implement whatever they like). However, what CDI provides is a strong (aka typesafe) mechanism to inject configuration-holding beans on one side, and a flexible producer mechanism to read and create such beans on the other side. Definitely this is the recommended way you were asking about.
The approach you are linking to is certainly a pretty good one - even though it might me too much for your needs, depending on the kind of properties you are planning to inject.
A very CDI-ish way of continuing would be to develop a CDI extension (that would nicely encapsulate all required classes) and deploy it independently with your projects. Of course you can also contribute to the CDI-extension catalog or even Apache Deltaspike.
See #ConfigProperty of Apache DeltaSpike
The only "standard" way of doing this would be to use a qualifier with a nonbinding annotation member, and make sure all of your injections are dependent scoped. Then in your producer you can get a hold of the InjectionPoint and get the key off the qualifier in the injection point. You'd want something like this:
#Qualifier
public #interface Property {
#Nonbinding String value default "";
}
...
#Inject #Property("myKey") String myKey;
...
#Produces #Property public String getPropertyByKey(InjectionPoint ip) {
Set<Annotation> qualifiers = ip.getQualifiers
// Loop through qualifers looking for Property.class save that off
return ResourceBundle.getBundle(...).getString(property.key);
}
There are obviously some enhancements you can do to that code, but it should be enough to get you started down the right track.
I have successfully set up a quick test of creating a "REST-like" service that returns an object serialized to JSON, and that was quite easy and quick (based on this article).
But while returning JSON-ified objects was easy as peach, I have yet to see any examples dealing with input parameters that are not primitives. How can I pass in a complex object as an argument? I am using Apache CXF, but examples using other frameworks like Jackson are welcome too :)
Client side would probably be something like building a javascript object, pass it into JSON.stringify(complexObj), and pass that string as one of the parameters.
The service would probably look something like this
#Service("myService")
class RestService {
#GET
#Produces("application/json")
#Path("/fooBar")
public Result fooBar(#QueryParam("foo") double foo, #QueryParam("bar") double bar,
#QueryParam("object") MyComplex object) throws WebServiceException {
...
}
}
Sending serialized objects as parameters would probably quickly touch the 2KB URL-limit imposed by Internet Explorer. Would you recommend using POST in these cases, and would I need to change much in the function definitions?
After digging a bit I quickly found out there are basically two options:
Option 1
You pass a "wrapper object" containing all the other parameters to the service. You might need to annotate this wrapper class with JAXB annotations like #XmlRootElement in order for this to work with the Jettison based provider, but if you use Jackson in stead there is no need. Just set the content type to the right type and the right message body reader will be invoked.
This will only work for POST type services of course (AFAIK).
Example
This is just an example of turning the service mentioned in the original question into one using a wrapper object.
#Service("myService")
class RestService {
#POST
#Produces("application/json")
#Path("/fooBar")
public Result fooBar(
/**
* Using "" will inject all form params directly into a ParamsWrapper
* #see http://cxf.apache.org/docs/jax-rs-basics.html
*/
#FormParam("") FooBarParamsWrapper wrapper
) throws WebServiceException {
doSomething(wrapper.foo);
}
}
class ParamsWrapper {
double foo, bar;
MyComplexObject object;
}
Option 2
You can provide some special string format that you pack your objects into and then implement either a constructor taking a string, a static valueOf(String s) or a static fromString(String s) in the class that will take this string and create an object from it. Or quite similar, create a ParameterHandler that does exactly the same.
AFAIK, only the second version will allow you to call your services from a browser using JSONP (since JSONP is a trick restricted to GET). I chose this route to be able to pass arrays of complex objects in the URI.
As an example of how this works, take the following domain class and service
Example
#GET
#Path("myService")
public void myService(#QueryParam("a") MyClass [] myVals) {
//do something
}
class MyClass {
public int foo;
public int bar;
/** Deserializes an Object of class MyClass from its JSON representation */
public static MyClass fromString(String jsonRepresentation) {
ObjectMapper mapper = new ObjectMapper(); //Jackson's JSON marshaller
MyClass o= null;
try {
o = mapper.readValue(jsonRepresentation, MyClass.class );
} catch (IOException e) {
throw new WebApplicationException()
}
return o;
}
}
A URI http://my-server.com/myService?a={"foo":1, "bar":2}&a={"foo":100, "bar":200} would in this case be deserialized into an array composed of two MyClass objects.
2019 comment:
Seeing that this answer still gets some hits in 2019, I feel I should comment. In hindsight, I would not recomment option 2, as going through these steps just to be able to be able to do GET calls adds complexity that's probably not worth it. If your service takes such complex input, you will probably not be able to utilize client side caching anyway, due to the number of permutations of your input. I'd just go for configuring proper Cross-Origin-Sharing (CORS) headers on the server and POST the input. Then focus on caching whatever you can on the server.
The accepted answer is missing #BeanParam. See
https://docs.jboss.org/resteasy/docs/3.0-rc-1/javadocs/javax/ws/rs/BeanParam.html
for further details. It allows you to define query params inside a wrapper object.
E.g.
public class TestPOJO {
#QueryParam("someQueryParam")
private boolean someQueryParam;
public boolean isSomeQueryParam() {
return someQueryParam;
}
public boolean setSomeQueryParam(boolean value) {
this.someQueryParam = value;
}
}
... // inside the Resource class
#GET
#Path("test")
public Response getTest(#BeanParam TestPOJO testPOJO) {
...
}
the best and simplest solution is to send your object as a json string and in server side implement a method which will decode that json and map to the specified object as per your need.. and yes it`s better to use POST.
I have this Grails domain class:
class Main {
Random r;
static constraints = {
}
}
and in database i see, that Random its - tinyblob.
In ORM DSL Documentation i not find indormation about this.
So, maybe, somebody can say me, why Random its a tinyblob?
It's a default mapping for an unknown class that will serialize into byte stream.
Here's an example of user type mapping, you can implement Hibernate mapper and register it in Config.groovy.
Still, I believe what you need is to declare the field transient:
class Main {
Random r = new Random()
static transients = ['r']
}
or just to have it private - private fields are not mapped by default.