3

This is what my Rest endpoint looks like

  @Post("json")
  public List<LogProcessorExpression> addLogProcessorExpression(
      final List<LogProcessorExpression> expressions) throws LPRestletException {
    if (expressions == null || expressions.isEmpty()) {
      return Collections.emptyList();
    }

    final Integer currentTenantId = Utils.getCurrentTenantId(getRequest());
    return customAttributesManager.addLogProcessorExpression(currentTenantId, expressions);
  }

the method it calls looks like

List<LogProcessorExpression> addLogProcessorExpression(final Integer currentTenantId,
                                                       final List<LogProcessorExpression> expressions)
      throws LPRestletException {
    final Map<String, LogProcessorExpression> cache = getCacheByCustomAttributeName(expressions);
    try {
      final List<Customattributesmetadata> cams =
          getCustomAttributesMetaDataForTenant(currentTenantId);

      for (final Customattributesmetadata metadata : cams) {
        if (cache.containsKey(metadata.getAttributecolumnname())) {
          metadata.setLogprocessorexpression(
              cache.get(metadata.getAttributecolumnname()).toString());
        }
        metadata.save();
      }
    } catch (final TorqueException e) {
      final String error = "Failed to update LogExpression custom attributes";
      LOGGER.error(error, e);
      throw new LPRestletException(error, e);
    }

    return expressions;
  }

which calls to other methods in chain. what I realized when accessing this endpoint as

 curl -v -H "Authorization:Basic Y3VyYasqrwqrjQGdtYWlsLmNvbTp0YXAzYWg=" \
     -H "Content-Type:application/json" \
     -d '[{"source": "ad", "attributePrefix": "ad_", "attributeName": "department"}]' \
     http://172.11.041.240:8080/api/rest/msp/attributes

That it returns

{
   "code" : 500
   "message" : "The server encountered an unexpected condition which prevented it from fulfilling the request",
}

When I looked at the logs, I see lines as

        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1515)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.shn.api.dto.LogProcessorExpression
        at com.shn.api.restlet.logprocessor.CustomAttributesManager.getCacheByCustomAttributeName(CustomAttributesManager.java:55)
        at com.shn.api.restlet.logprocessor.CustomAttributesManager.addLogProcessorExpression(CustomAttributesManager.java:24)
        at com.shn.api.restlet.logprocessor.CustomAttributeMetadataRestlet.addLogProcessorExpression(CustomAttributeMetadataRestlet.java:44)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.restlet.resource.ServerResource.doHandle(ServerResource.java:521)
        ... 67 more

Question
- Why is it not casting them to List<LogProcessorExpression>?
- What do I need to do to fix it?

UPDATE

Line 24 looks like

final Map<String, LogProcessorExpression> cache = getCacheByCustomAttributeName(expressions);  

Line 44 looks like

return customAttributesManager.addLogProcessorExpression(currentTenantId, expressions);  

getCacheByCustomAttributeName(expressions) looks like

  Map<String, LogProcessorExpression> getCacheByCustomAttributeName(
      final List<LogProcessorExpression> expressions) {
    if (expressions == null || expressions.isEmpty()) {
      return Collections.emptyMap();
    }

    final Map<String, LogProcessorExpression> attributeByExpression = new HashMap<>();
    for (final LogProcessorExpression expression : expressions) {
      attributeByExpression.put(expression.getAttributeName(), expression);
    }
    return attributeByExpression;
  }
daydreamer
  • 87,243
  • 191
  • 450
  • 722

3 Answers3

4

I think restlet might not be sophisticated enough to extract the parameterized type List<LogProcessorExpression> from your handler method's parameter list.

@Post("json")
public List<LogProcessorExpression> addLogProcessorExpression(
  final List<LogProcessorExpression> expressions)

It just takes List and presumably uses that when deserializing (with Jackson). Jackson uses LinkedHashMap as a deserialization target type when one isn't provided.

Short of restlet implementing this better (maybe in a newer version?), a potential solution is to define a custom type

class LogProcessorExpressionList extends ArrayList<LogProcessorExpression> {}

and using that type as the parameter type

@Post("json")
public List<LogProcessorExpression> addLogProcessorExpression(
  final LogProcessorExpressionList expressions)

Jackson can then extract the parameterized super type of the type LogProcessorExpressionList, which is ArrayList<LogProcessorExpression>, from which it can extract LogProcessorExpression as the target element type.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • Interesting, now I see `{"code":422,"message":"The server understands the content type of the request entity and the syntax of the request entity is correct but was unable to process the contained instructions"}` – daydreamer May 20 '15 at 06:24
  • I needed Getters/Setters and empty Constructor for `LogProcessorExpression` and that solved the problem with your solution – daydreamer May 20 '15 at 14:40
0

Perhaps could you use a custom Jackson deserializer for this? See this link for this feature: http://www.baeldung.com/jackson-deserialization.

This answer gives you some hints to configuration the Jackson ObjectMapper: How to register Jackson Jdk8 module in Restlet. This allows to register the custom deserializer and have the hand on the deserialization processing to create the right object within your list.

Hope it helps you, Thierry

Community
  • 1
  • 1
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
0

This is worked for me..

class LogProcessorExpressionList extends ArrayList<LogProcessorExpression> {}