How can I replace JSON Converter with my own - json

I'm looking to use JACKSON instead of grails JSON ,without changing the auto-scaffolded contollers.
Is it possible to seamlessly replace the current grails JSON converter with another one ?
Are there any classes to implement other then AbstractConverter...

Should be pretty simple. AbstractConverter is all you need to extend to do:
render result as JackSON
Something like this***:
*** taken from here: https://github.com/sjhorn/grails-jackson/blob/master/src/groovy/com/hornmicro/JackSON.groovy
class JackSON extends AbstractConverter {
Object target
public JackSON() {
}
public JackSON(Object target) {
this()
setTarget(target)
}
public void render(Writer out) throws ConverterException {
try {
ObjectMapper mapper = new ObjectMapper()
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
mapper.configure(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM, false)
mapper.configure(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT, false)
mapper.writeValue(out, target)
} catch(e) {
throw new ConverterException(e)
}
try {
out.flush()
out.close()
} catch (Exception e) {
log.warn("Unexpected exception while closing a writer: " + e.getMessage())
}
}
public void render(HttpServletResponse response) throws ConverterException {
response.setContentType(GrailsWebUtil.getContentType("application/json", "UTF-8"));
try {
render(response.getWriter())
} catch (IOException e) {
throw new ConverterException(e)
}
}
public Object getWriter() throws ConverterException {
throw new ConverterException("Not Implemented")
}
public void convertAnother(Object o) throws ConverterException {
throw new ConverterException("Not Implemented")
}
public void build(Closure c) throws ConverterException {
throw new ConverterException("Not Implemented")
}
public ObjectMarshaller lookupObjectMarshaller(Object target) {
return null
}
public void setTarget(Object target) {
this.target = target
}
}

Related

Need only the stream for response while using Apache Async http client

I am using Apache Async Http Client to download huge files from Azure Storage.
This is the sample code I am using ->
CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
httpclient.execute(request, new FutureCallback<org.apache.http.HttpResponse>() {
#Override
public void completed(final org.apache.http.HttpResponse httpResponse) {
}
#Override
public void failed(final Exception e) {
future.completeExceptionally(e);
}
#Override
public void cancelled() {
future.completeExceptionally(new Exception("Request cancelled"));
}
});
But this is storing the file in a local buffer before invoking completed callback .
I tried using AsyncByteConsumer ->
AsyncByteConsumer<org.apache.http.HttpResponse>
consumer = new AsyncByteConsumer<org.apache.http.HttpResponse>() {
#Override
protected void onByteReceived(ByteBuffer buf, IOControl ioctrl) throws IOException {
}
#Override
protected void onResponseReceived(org.apache.http.HttpResponse response) throws HttpException, IOException {
}
#Override
protected org.apache.http.HttpResponse buildResult(HttpContext context) throws Exception {
return null;
}
};
This also did not work for me.
I am getting the following error ->
java.lang.IllegalStateException: Content has not been provided
All I want is to get the stream for the response which I will pass on to my clients so that they can download the file directly using the stream.
EDIT 1 ->
So I extended AbstractAsyncResponseConsumer to write my own consumer ->
public abstract class MyConsumer extends AbstractAsyncResponseConsumer<HttpResponse> {
private volatile HttpResponse response;
private volatile SimpleInputBuffer buf;
public MyConsumer() {
super();
}
#Override
protected void onResponseReceived(HttpResponse response) {
this.response = response;
}
#Override
protected void onContentReceived(ContentDecoder decoder, IOControl ioctrl) throws IOException {
Asserts.notNull(this.buf, "Content buffer");
System.out.println("onContentReceived");
buf.consumeContent(decoder);
}
protected abstract void onEntitySet(HttpResponse httpResponse);
#Override
protected void onEntityEnclosed(HttpEntity entity, ContentType contentType) throws IOException {
System.out.println("onEntityEnclosed");
long len = entity.getContentLength();
if (len > Integer.MAX_VALUE) {
throw new ContentTooLongException("Entity content is too long: " + len);
}
if (len < 0) {
len = 4096;
}
this.buf = new SimpleInputBuffer((int) len, new HeapByteBufferAllocator());
this.response.setEntity(new ContentBufferEntity(entity, this.buf));
onEntitySet(this.response);
}
#Override
protected HttpResponse buildResult(HttpContext context) throws Exception {
System.out.println("buildResult");
return response;
}
#Override
protected void releaseResources() {
}
}
Here is the code I am using to execute a http request
CompletableFuture<HttpResponse> makeRequest() {
HttpAsyncRequestProducer producer3 = HttpAsyncMethods.create(request);
CompletableFuture<HttpResponse> future = new CompletableFuture<>();
httpclient.execute(producer3, new MyConsumer() {
#Override
protected void onEntitySet(HttpResponse httpResponse) {
future.complete(httpResponse);
}
},
new FutureCallback<HttpResponse>() {
#Override
public void completed(HttpResponse result) {
System.out.println("Completed" + result);
}
#Override
public void failed(Exception ex) {
}
#Override
public void cancelled() {
}
});
}
makeRequest().thenAccept((HttpResponse httpResponse) -> {
try {
System.out.println(IOUtils.toString(httpResponse.getEntity().getContent()));
} catch (IOException e) {
e.printStackTrace();
}
});
I am getting this output ->
onEntityEnclosed .
java.io.IOException: Underlying input stream returned zero bytes .
I am completing the response future as soon as I am getting the onResponseReceived callback which returns the status and headers of the response.
What I believe should happen is that onContentReceived callback will be invoked in a separate thread which will write the buffer data to the stream and my caller thread can read it in a separate thread.
I am not sure why you are having those problems but the following code snippet works for me (using HttpAsyncClient 4.1.3)
CloseableHttpAsyncClient httpClient = HttpAsyncClients.createDefault();
httpClient.start();
final Future<Void> future = httpClient.execute(
HttpAsyncMethods.createGet("http://httpbin.org/"),
new AsyncByteConsumer<Void>() {
#Override
protected void onByteReceived(final ByteBuffer buf, final IOControl ioctrl) throws IOException {
System.out.println(buf.remaining());
}
#Override
protected void onResponseReceived(final HttpResponse response) throws HttpException, IOException {
System.out.println(response.getStatusLine());
}
#Override
protected Void buildResult(final HttpContext context) throws Exception {
return null;
}
},
null);
future.get();
httpClient.close();
console >
HTTP/1.1 200 OK
1060
8192
3877

catch exception if boolean is false

This is the easiest example of a complex issue. I haven't found the example of this problem anywhere in the entire internet. I'm validating the input in a validationMethod that return Boolean. Now, I need to use this method in calling class (run the flow if return is true, catch exception if return is false).
public class StringUtil{
public static boolean validateNumInput(String UserInput)
{
if(UserInput.matches("[0-9]+")){
return true;
} return false;
}
}
public class Main{
public static void main(String[] args){
String a="012*+";
try{
if(StringUtil.validateNumInput(a)){
System.out.println(StringUtil.validateNumInput(a));
}
}catch(Exception e){
System.out.println("Big problem");
}
}
}
According to the documentation, you can filter catch clauses with a Boolean predicate. So, your validation method would need to throw an exception which you could filter for in your catch clause. But if you're doing that, you might as well roll your own custom exception and not have to deal with the Boolean at all. The other alternative is, in your calling code, treat the return code as a return code and throw your own exception.
Option 1:
public class StringUtil{
public static boolean validateNumInput(String UserInput)
{
if(UserInput.matches("[0-9]+")){
return true;
}
throw new Exception ("Validation failed!");
}
}
public class Main{
public static void main(String[] args){
String a="012*+";
try{
if(StringUtil.validateNumInput(a)){
System.out.println(StringUtil.validateNumInput(a));
}
}catch(Exception e) when (e.Message == "Validation failed!") {
System.out.println("Big problem");
}
}
}
Option 2:
public class Main{
public static void main(String[] args){
String a="012*+";
try{
if(StringUtil.validateNumInput(a)){
System.out.println(StringUtil.validateNumInput(a));
} else {
throw new Exception ();
}
}catch(Exception e) {
System.out.println("Big problem");
}
}
}

org.codehaus.jackson.JsonGenerationException: Can not write number, expecting field name

Hi i am working on a spring mvc application well i need to Serialize an object in order to pass it with an ajax Post.
my bean class :
#JsonSerialize(using = AgentSer.class)
public class AgentCust implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Long personneID;
private String nom;
private String prenom;
private String matriculation;
private String marche;
private String compte;
private String phone, mail, chat;
public String getMarche() {
return marche;
}
public void setMarche(String marche) {
this.marche = marche;
}
public String getCompte() {
return compte;
}
public void setCompte(String compte) {
this.compte = compte;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getMail() {
return mail;
}
public void setMail(String mail) {
this.mail = mail;
}
public String getChat() {
return chat;
}
public void setChat(String chat) {
this.chat = chat;
}
public Long getPersonneID() {
return personneID;
}
public void setPersonneID(Long personneID) {
this.personneID = personneID;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public String getPrenom() {
return prenom;
}
public void setPrenom(String prenom) {
this.prenom = prenom;
}
public String getMatriculation() {
return matriculation;
}
public void setMatriculation(String matriculation) {
this.matriculation = matriculation;
}
}
and the class that will serialize my bean :
public class AgentSer extends JsonSerializer<AgentCust> {
#Override
public void serialize(AgentCust value, JsonGenerator jgen, SerializerProvider arg2) throws IOException, JsonProcessingException {
// TODO Auto-generated method stub
jgen.writeStartObject();
jgen.writeNumber(value.getPersonneID());
jgen.writeString(value.getMatriculation());
jgen.writeString(value.getNom());
jgen.writeString(value.getPrenom());
jgen.writeString(value.getCompte());
jgen.writeString(value.getMarche());
jgen.writeString(value.getChat());
jgen.writeString(value.getMail());
jgen.writeString(value.getPhone());
jgen.writeEndObject();
}
}
in my controller i use my class like that:
AgentCust ags ;
// i set values here .
ObjectMapper mapper = new ObjectMapper();
String json = "";
try {
json = mapper.writeValueAsString(ags);
} catch (Exception e) {
System.out.println(e);
}
but at the end i get that :
org.codehaus.jackson.JsonGenerationException: Can not write number, expecting field name
any help please.
Why are you using a custom serializer(which is wrong as it doesn't include the field names). You are really complicating your life.
You can set the serialization options like this (you can also set them in a static block):
final ObjectMapper mapper = new ObjectMapper();
/*
you can set them globally in a static block and reuse the mapper...
performance gain
*/
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
mapper.configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false);
mapper.setSerializationInclusion(Include.NON_NULL);
The rest of the code is the same(just add a constructor in your AgentCust.class to avoid some mapping errors):
AgentCust ags = new AgentCust();
ags.setChat("chat1");
ags.setCompte("compte1");
ags.setMail("mail1");
ags.setMarche("marche1");
ags.setMatriculation("matriculation1");
ags.setNom("nom1");
ags.setPersonneID(123456L);
ags.setPhone("phone1");
ags.setPrenom("prenom1");
String json = "";
try {
json = mapper.writeValueAsString(ags);
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(json);
Another strange thing is that you're serializing the pojo as String. Why not JsonNode or ObjectNode?
public static ObjectNode convObjToONode(Object o) {
StringWriter stringify = new StringWriter();
ObjectNode objToONode = null;
try {
mapper.writeValue(stringify, o);
objToONode = (ObjectNode) mapper.readTree(stringify.toString());
} catch (JsonMappingException e) {
Logger.error("ERROR MAPPING JSON from object!", e);
} catch (JsonGenerationException e) {
Logger.error("ERROR GENERATING JSON from object!", e);
} catch (IOException e) {
Logger.error("ERROR IO when writing JSON from object!", e);
}
Logger.debug("Object as ObjectNode : " + objToONode);
return objToONode;
}

Is there a way to ignore JsonSyntaxException in Gson

I have a json that looks like this:
[
{
_id: "54b8f62fa08c286b08449b8f",
loc: [
36.860983,
31.0567
]
},
{
_id: "54b8f6aea08c286b08449b93",
loc: {
coordinates: [ ]
}
}
]
As you can see, loc object is sometimes is a json object, sometimes is a double array. Without writing a custom deserializer, is there a way to avoid JsonSyntaxException and set the loc object to null when it is a json object rather than a double array.
There aren't any easy way (I mean a property/method call at Gson) for custom seralization/deserialization of a specific field at a json value.
You can see source code of com.google.gson.internal.bind.ReflectiveTypeAdapterFactory, and debug on its inner class Adapter's read method. (That's where your JsonSyntaxException occurs)
You can read Custom serialization for JUST specific fields and track its links. It may be implemented at future release of Gson. (Not available at latest release 2.2.4)
I would write some code for this. Maybe that's not what you are looking for but it may help somebody else.)
Solution 1 (This has less code compared with the second solution but second solution's performance is much more better):
public class SubClass extends BaseClass {
private double[] loc;
}
public class BaseClass {
#SerializedName("_id")
private String id;
}
public class CustomTypeAdapter extends TypeAdapter<BaseClass> {
private Gson gson;
public CustomTypeAdapter() {
this.gson = new Gson();
}
#Override
public void write(JsonWriter out, BaseClass value)
throws IOException {
throw new RuntimeException("Not implemented for this question!");
}
#Override
public BaseClass read(JsonReader in) throws IOException {
BaseClass instance;
try {
instance = gson.fromJson(in, SubClass.class);
} catch (Exception e) {
e.printStackTrace();
instance = gson.fromJson(in, BaseClass.class);
}
return instance;
}
}
Test:
private void test() {
String json = "[{_id:\"54b8f62fa08c286b08449b8f\",loc:[36.860983,31.0567]},{_id:\"54b8f6aea08c286b08449b93\",loc:{coordinates:[]}}]";
Type collectionType = new TypeToken<List<BaseClass>>(){}.getType();
Gson gson = new GsonBuilder().registerTypeAdapter(BaseClass.class, new CustomTypeAdapter()).create();
List<BaseClass> list = gson.fromJson(json, collectionType);
for(BaseClass item : list) {
if(item instanceof SubClass) {
System.out.println("item has loc value");
SubClass subClassInstance = (SubClass)item;
} else {
System.out.println("item has no loc value");
BaseClass baseClassInstance = item;
}
}
}
Solution 2 (It is one of the Gson Developers suggestion. See original post.):
Copy below class to your project. It is going to be a base class for your custom TypeAdapterFactorys.
public abstract class CustomizedTypeAdapterFactory<C>
implements TypeAdapterFactory {
private final Class<C> customizedClass;
public CustomizedTypeAdapterFactory(Class<C> customizedClass) {
this.customizedClass = customizedClass;
}
#SuppressWarnings("unchecked") // we use a runtime check to guarantee that 'C' and 'T' are equal
public final <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
return type.getRawType() == customizedClass
? (TypeAdapter<T>) customizeMyClassAdapter(gson, (TypeToken<C>) type)
: null;
}
private TypeAdapter<C> customizeMyClassAdapter(Gson gson, TypeToken<C> type) {
final TypeAdapter<C> delegate = gson.getDelegateAdapter(this, type);
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
return new TypeAdapter<C>() {
#Override public void write(JsonWriter out, C value) throws IOException {
JsonElement tree = delegate.toJsonTree(value);
beforeWrite(value, tree);
elementAdapter.write(out, tree);
}
#Override public C read(JsonReader in) throws IOException {
JsonElement tree = elementAdapter.read(in);
afterRead(tree);
return delegate.fromJsonTree(tree);
}
};
}
/**
* Override this to muck with {#code toSerialize} before it is written to
* the outgoing JSON stream.
*/
protected void beforeWrite(C source, JsonElement toSerialize) {
}
/**
* Override this to muck with {#code deserialized} before it parsed into
* the application type.
*/
protected void afterRead(JsonElement deserialized) {
}
}
Write your POJO and your custom CustomizedTypeAdapterFactory. Override afterRead method and handle double array as you asked at your question:
public class MyClass {
#SerializedName("_id")
private String id;
private double[] loc;
// getters/setters
}
private class MyClassTypeAdapterFactory extends CustomizedTypeAdapterFactory<MyClass> {
private MyClassTypeAdapterFactory() {
super(MyClass.class);
}
#Override protected void afterRead(JsonElement deserialized) {
try {
JsonArray jsonArray = deserialized.getAsJsonObject().get("loc").getAsJsonArray();
System.out.println("loc is not a double array, its ignored!");
} catch (Exception e) {
deserialized.getAsJsonObject().remove("loc");
}
}
}
Test:
private void test() {
String json = "[{_id:\"54b8f62fa08c286b08449b8f\",loc:[36.860983,31.0567]},{_id:\"54b8f6aea08c286b08449b93\",loc:{coordinates:[]}}]";
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new MyClassTypeAdapterFactory())
.create();
Type collectionType = new TypeToken<List<MyClass>>(){}.getType();
List<MyClass> list = gson.fromJson(json, collectionType);
for(MyClass item : list) {
if(item.getLoc() != null) {
System.out.println("item has loc value");
} else {
System.out.println("item has no loc value");
}
}
}
This is how I did this. It is shorter, but I think #DevrimTuncers answer is the best one.
//This is just Double array to use as location object
public class Location extends ArrayList<Double> {
public Double getLatidute() {
if (this.size() > 0) {
return this.get(0);
} else {
return (double) 0;
}
}
public Double getLongitude() {
if (this.size() > 1) {
return this.get(1);
} else {
return (double) 0;
}
}
public static class LocationDeserializer implements JsonDeserializer<Location> {
#Override
public Location deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
try {
JsonArray array = json.getAsJsonArray();
Location location = new Location();
for (int i = 0; i < array.size(); i++) {
location.add(array.get(i).getAsDouble());
}
return location;
} catch (Exception e) {
return null;
}
}
}
}

How Can I log exception stacktrace via custom junit runner?

Hi I have custom junit runner
public class InterceptorRunner extends BlockJUnit4ClassRunner {
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface InterceptorClasses {
public Class<?>[] value();
}
public InterceptorRunner(Class<?> klass) throws InitializationError {
super(klass);
}
#Override
public Statement methodInvoker(FrameworkMethod method, Object test) {
InterceptorStatement statement = new InterceptorStatement(super.methodInvoker(method, test));
InterceptorClasses annotation = test.getClass().getAnnotation(InterceptorClasses.class);
Class<?>[] klasez = annotation.value();
try {
for (Class<?> klaz : klasez) {
statement.addInterceptor((Interceptor) klaz.newInstance());
}
} catch (IllegalAccessException ilex) {
ilex.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return statement;
}
#Override
public void run(RunNotifier notifier) {
FailListener listener = new FailListener();
notifier.addListener(listener);
super.run(notifier);
notifier.removeListener(listener);
}
}
and custom listener
public class FailListener extends RunListener {
#Override
public void testFailure(Failure failure) throws Exception {
System.out.println("test fails");
super.testFailure(failure);
}
public void testStarted(Description description) throws Exception {
System.out.println("Test started");
super.testStarted(description);
}
}
How can I log not only System.out.println("test fails"); but also Exception and some other information?
It seems to me that it possible to use failure, but I don't know how to.
The Failure object has a method getException().