I want to load an objet and forget that it comes from hibernate! That's it, I just do something as:
MyClass myObject = MyClassDAO.getUnproxiedObject(objectID);
and than I have a real instance of myObj (and not from a Hibernate proxy) with all attributes set with the values from the database, so that I can't distinguish it from a manually created object.
In this thread a method is present to create an unproxied object, but it does not treats the issue of eager loding the objects, what I suppose is necessary for achieving my ultimate goals.
For those who are wondering why would I want such objects, I need to serialize then to Json with Gson, but I think it would have many other uses for many people.
Use FetchType.EAGER to eagerly load all the relations. Specifically for JSON serialization, if you are building a web application consider using an OpenSessionInView interceptor for your HTTP requests.
after testing I found out that the method given in the citted post did exactly what I was looking for.
The reason hibernate doesn't de-proxy while rendering with GSON is that GSON uses reflection to serialize the fields rather than using the getters of the Hibernate object. To workaround, you need to register a new TypeHierarchyAdapter that will de-proxy the object as GSON is serializing.
Here's my approach:
GsonBuilder builder = new GsonBuilder();
builder.registerTypeHierarchyAdapter(HibernateProxy.class, new HibernateProxySerializer());
String jsonLove = gson.toJson(objToSerialize);
Here's the HibernateProxySerializer:
public class HibernateProxySerializer implements JsonSerializer<HibernateProxy> {
#Override
public JsonElement serialize(HibernateProxy proxyObj, Type arg1, JsonSerializationContext arg2) {
try {
GsonBuilder gsonBuilder = new GsonBuilder();
//below ensures deep deproxied serialization
gsonBuilder.registerTypeHierarchyAdapter(HibernateProxy.class, new HibernateProxySerializer());
Object deProxied = proxyObj.getHibernateLazyInitializer().getImplementation();
return gsonBuilder.create().toJsonTree(deProxied);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Related
I have a unique requirement where i need to construct a JSON as below.
{
"XXXMonitoring/DC/EVN/DBNAME":{
"t":123456777,
"s":{
"CAPTURE":{
"c":100
}
}
}
}
where the root element "XXXMonitoring/DC/EVN/DBNAME" contains "/" in between as it represents a path. I tried with GSON to have nested java but not sure how i can represent "XXXMonitoring/DC/EVN/DBNAME" from my Java object.
Can someone help me on this.
I'm not sure if this is what are you asking...
But sollidus (/) is escaped by backslash (\) to be sure that the browser won’t mistake it for the closing script tag
when you need to use that key, you can remove backslash with String.replaceAll() method
json.toString().replaceAll("\\\\", "");
The JSON string can be constructed without POJO class using the below code.
If the JSON structure is same and only values will change for the keys, you can replace the hard coded values with variables and convert this into an utility method. The utility method can be reused to generate the JSON string.
public static void main(String[] args) throws IOException {
Gson gson = new Gson();
JsonObject jsonRootObject = new JsonObject();
JsonObject jsonFirstLevelObject = new JsonObject();
// t property
jsonFirstLevelObject.addProperty("t", 123456777);
JsonObject jsonCaptureObject = new JsonObject();
JsonObject jsonCObject = new JsonObject();
jsonCObject.addProperty("c", 100);
jsonCaptureObject.add("CAPTURE", jsonCObject);
// s property
jsonFirstLevelObject.add("s", jsonCaptureObject);
jsonRootObject.add("XXXMonitoring/DC/EVN/DBNAME", jsonFirstLevelObject);
System.out.println(gson.toJson(jsonRootObject));
}
I have a library called GsonPath which might suit your needs. The aim of the library is to provide an annotation processor that generates the boilerplate code to help simplify the POJO you need to write.
By using the library you can write a POJO similar to the following:
#AutoGsonAdapter(rootField = "XXXMonitoring/DC/EVN/DBNAME")
public class SamplePojo {
int t;
#SerializedName("s.CAPTURE.c")
int sCapture;
}
Then all you need to do in your gson object is to register a special TypeAdapterFactory
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapterFactory(GsonPath.createTypeAdapterFactory());
Gson gson = builder.create();
The documentation within the library is faily comprehensive, let me know if you have any problems!
I'm trying to serialize an object with several lazily loaded properties, and I'm getting the following error:
Could not write content: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
After some searching I have tried this in my #Configuration class, but it doesn't seem to help:
#Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
Hibernate4Module hibernateModule = new Hibernate4Module();
hibernateModule.configure(Hibernate4Module.Feature.FORCE_LAZY_LOADING, false);
objectMapper.registerModule(hibernateModule);
return objectMapper;
}
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper());
return converter;
}
When I change to FetchType.EAGER the application works fine.
The problem is related to the fact that related objects to the main one are not really loaded when you execute the query and not use the FetchType.EAGER; by using the FetchType.EAGER you tell hibernate: load the main entity and all the related entities; this can have not too much sense (you can risk to load all the database in one query)
Returning to jackson marshaller, when objects are "proxied" it is not able in serializing them
IMHO i'd do the following:
i'd create a DTO object to be serialized (I'd not serialize the Hibernate object)
i'd put in this DTO only the needed properties and data
if user need to see related objects a specific call would be executed and data related to the selected object will be loaded from DB and serialized (in specific DTO objects)
Similar to Jersey: Json array with 1 element is serialized as object BUT on the client side. E.g. I recieve a JSON object where a field is an array regulary, but in case there is only one element, it is a single object.
{"fileInfo":[{"fileName":"weather.arff","id":"10"},"fileName":"supermarket.arff","id":"11"}]}
versus
{"fileInfo":{"fileName":"weather.arff","id":"10"}}
I'm parsing/unmarshalling the JSON using Jersey/Genson. Of course, if the JSON doesnt match the target class I recieve an error (such as expected [ but read '{' )
I've read a lot about this bug and how to avoid when creating JSON objects on the SERVER side, but I found nothing about how to handle this issus when dealing on the CLIENT side.
As always, I prefere the most codeless possibility if there are several solutions...
BTW: Moxy works but it does not marshal native Object-type objects which is another requirement...
Update
Starting with Genson 1.3 release you can achieve it by enabling permissiveParsing:
Genson genson = new GensonBuilder().usePermissiveParsing(true).create();
Answer
Uh, do you know what library produces this on server side? I am curious to see who is responsible for all those badly structured jsons out there...
It is not yet supported in Genson. Originally because IMO people should not produce such dynamic json. Anyway, I opened an issue - this can be easily done, you can expect it to be present in the release coming next week.
Otherwise here is a way to achieve it without breaking the existing mechanisms.
You need to register a Factory that will use Gensons collections factory to create an instance of its standard collection converter. Then you will wrap this converter in another one that will handle the object to array logic. Here is the code (not codeless..., but if you wait a bit you won't have to code :)).
import com.owlike.genson.convert.DefaultConverters.CollectionConverterFactory;
import com.owlike.genson.convert.DefaultConverters.CollectionConverterFactory;
class SingleObjectAsCollectionFactory implements Factory<Converter<Collection>> {
// get the default factory
Factory<Converter<Collection<?>>> defaultFactory = CollectionConverterFactory.instance;
#Override
public Converter<Collection> create(Type type, Genson genson) {
// obtain an instance of the correct default converter for this type
final CollectionConverter defaultConverter = (CollectionConverter) defaultFactory.create(type, genson);
// wrap it in your own converter
return new Converter<Collection>() {
#Override
public void serialize(Collection object, ObjectWriter writer, Context ctx) throws Exception {
defaultConverter.serialize(object, writer, ctx);
}
#Override
public Collection deserialize(ObjectReader reader, Context ctx) throws Exception {
if (reader.getValueType() == ValueType.OBJECT) {
Object object = defaultConverter.getElementConverter().deserialize(reader, ctx);
Collection result = defaultConverter.create();
result.add(object);
return result;
} else return defaultConverter.deserialize( reader, ctx );
}
};
}
}
And then register it
Genson genson = new GensonBuilder()
.withConverterFactory(new SingleObjectAsCollectionFactory())
.create();
I need to pass a map back to the web application.
I'm used to encapsulating the map in a JSONObject
http://json.org/java/
But since I am using Spring and Jackson Haus.
is there an easier way to maintain the pojo? May I can just annotate the MAP ?
Jackson has com.fasterxml.jackson.core.JsonNode, and specific subtypes like ObjectNode.
These form so-called Tree Model, which is one of 3 ways to handle JSON with Jackson -- some other libraries (like org.json) only offer this way.
So you should be able to just use JsonNode instead; there is little point in using org.json library; it is slow, and has outdated API.
Alternatively you can just use java.util.Map, and return that. Jackson can handle standard Lists, Maps and other JDK types just fine.
If you need to manipulate the output, ie, you don't want to provide all the fields of the object you can use JSonArray:
#RequestMapping(value = "/api/users", method = RequestMethod.GET)
public
#ResponseBody
String listUsersJson(ModelMap model) throws JSONException {
JSONArray userArray = new JSONArray();
for (User user : userRepository.findAll()) {
JSONObject userJSON = new JSONObject();
userJSON.put("id", user.getId());
userJSON.put("firstName", user.getFirstName());
userJSON.put("lastName", user.getLastName());
userJSON.put("email", user.getEmail());
userArray.put(userJSON);
}
return userArray.toString();
}
Use the example from here
Otherwise if you add jackson to your dependencies and set the controller method anotatted with #ResponseBody the response will automatically mapped to JSON. Check here for a simple example.
In my project we serialize disconnected Linq-to-SQL entities (mainly to preserve them between postbacks). Code in use for that is fairly straightforward:
public static string Serialize<P>(this P entity)
{
StringWriter writer = new StringWriter();
XmlTextWriter xmlWriter = new XmlTextWriter(writer);
DataContractSerializer serializer = new DataContractSerializer(typeof(P));
serializer.WriteObject(xmlWriter, entity);
return writer.ToString();
}
It works fine, but after deserialization all EntityRef's children for that object are gone and replaced with just a foreign key value. Looks like this problem is due to the lack of bi-directional serialization.
Is there existing work around for this problem?
Try changing the Serialization Mode property to "Unidirectional" on the Linq2Sql Dbml file. I ran into this issue when using L2S in a web service.