I'm trying to create that uses the java_rosbridge library, but I am having issues with accessing and updating the variable status between class scopes.
Boolean isDoorbellRinging() {
Boolean status = false;
bridge.subscribe(SubscriptionRequestMsg.generate("/doorbell").setType("std_msgs/Bool").setThrottleRate(1)
.setQueueLength(1), new RosListenDelegate() {
public void receive(JsonNode data, String stringRep) {
MessageUnpacker<PrimitiveMsg<String>> unpacker = new MessageUnpacker<PrimitiveMsg<String>>(
PrimitiveMsg.class);
PrimitiveMsg<String> msg = unpacker.unpackRosMessage(data);
logger.info(data.get("msg").get("data").asText());
status = ((data.get("msg").get("data").asInt() > 0) ? true : false);
}
});
return status;
}
It's receiving the data correctly as I get the correct output with logger.info(..) when not trying to access status. However, when including status = ((data.get("msg")...
I'm currently receiving this error:
Local variables referenced from an inner class must be final or effectively final
What that message means, is that in closures (lambdas and methods in anonymous classes), after their definition, variables from outer scope must not be reassigned. You can circumvent this using containers (collections, arrays, atomics, and so on). In this case, AtomicBoolean may come in handy: define your variable as AtomicBoolean and use set instead of assignment. If you have to distinguish between null and false, use AtomicReference<Boolean>.
'status' is on a stack frame corresponding to the execution of isDoorbellRinging().
The 'receive' call presumably will execute at some future time. At that point, isDoorbellRinging() will have returned. There will be no 'status' to modify. It will have ceased to be.
By the same point, isDoorbellRinging() cannot 'now' return a value that will be determined at some point in the future.
You need some way to handle the asynchronous nature of this.
Related
I'm having an issue with the unless condition of the Cacheable annotation.
From the documentation, I understand that the unless condition is verified after the method being annotated is called and the value the method returns is cached (and actually returned) only if the unless condition is not met. Otherwise, the cached value should be returned.
Firstly, is this assumption true?
EDIT:
[From the Spring documentation] As the name implies, #Cacheable is used
to demarcate methods that are cacheable - that is, methods for whom
the result is stored into the cache so on subsequent invocations (with
the same arguments), the value in the cache is returned without having
to actually execute the method.
[My understanding] So for a given key, the method will be always executed until the unless condition is not met once. Then the cached value will be
returned for all subsequent calls to the method.
To illustrate my issue, I tried to break down my code into four simples classes:
1) DummyObject that represents instances to be cached and retrieved. It's a timestamp wrapper to show what is last value that has been cached. The toBeCached boolean is a flag that should be checked in the unless condition to know if the instance returned should be cached or not.
2) DummyDAO that returns DummyObject instances based on provided keys. Upon retrieval of an instance, the DAO checks when was the last value retrieved and verified if it should be cached or not (independently of what key is provided. Doesn't matter if this logic is "broken" as I'm always using the same key for my example). The DAO then marks the instance returned with the flag toBeCached. If the value is marked to be cached, the DAO actually updates its lastRetrieved timestamp as the instance should be eventually cached by the CachedDAO (because the unless condition won't be met).
3) DummyCachedDao that calls the DummyDAO to retrieve instances of DummyObject. If instances are marked toBeCached, it should cache the newly returned value. It should return the previously cached value otherwise.
4) The Application that retrieves a value (that will be cached), sleeps for a short time (not long enough for the cache duration to pass), retrieves a value (that should be the cached one), sleeps again (long enough for cache duration to pass), retrieves again a value (that should be a new value to be cached).
Unfortunately, this code does not work as expected as the retrieved value is always the original value that has been cached.
To ensure that the logic worked as expected, I checked if the unless conditions are met or not by replacing the retrieveTimestamp by retrieveTimestampBypass in the Application class. Since internal calls bypass the Spring proxy, the retrieveTimestamp method and whatever breakpoints or logs I put in are actually caught/shown.
What would cause the value to never be cached again? Does the cache need to be clean from previous values first?
public class DummyObject
{
private long timestamp;
private boolean toBeCached;
public DummyObject(long timestamp, boolean toBeCached)
{
this.timestamp = timestamp;
this.toBeCached = toBeCached;
}
public long getTimestamp()
{
return timestamp;
}
public boolean isToBeCached()
{
return toBeCached;
}
}
#Service
public class DummyDAO
{
private long cacheDuration = 3000;
private long lastRetrieved;
public DummyObject retrieveTimestamp(String key)
{
long renewalTime = lastRetrieved + cacheDuration;
long time = System.currentTimeMillis();
boolean markedToBeCached = renewalTime < time;
System.out.println(renewalTime + " < " + time + " = " + markedToBeCached);
if(markedToBeCached)
{
lastRetrieved = time;
}
return new DummyObject(time, markedToBeCached);
}
}
#Service
public class DummyCachedDAO
{
#Autowired
private DummyDAO dao;
// to check the flow.
public DummyObject retrieveTimestampBypass(String key)
{
return retrieveTimestamp(key);
}
#Cacheable(cacheNames = "timestamps", unless = "#result.isToBeCached() != true")
public DummyObject retrieveTimestamp(String key)
{
return dao.retrieveTimestamp(key);
}
}
#SpringBootApplication
#EnableCaching
public class Application
{
public final static String KEY = "cache";
public final static String MESSAGE = "Cached timestamp is: %s [%s]";
public static void main(String[] args) throws InterruptedException
{
SpringApplication app = new SpringApplication(Application.class);
ApplicationContext context = app.run(args);
DummyCachedDAO cache = (DummyCachedDAO) context.getBean(DummyCachedDAO.class);
// new value
long value = cache.retrieveTimestamp(KEY).getTimestamp();
System.out.println(String.format(MESSAGE, value, new Date(value)));
Thread.sleep(1000);
// expecting same value
value = cache.retrieveTimestamp(KEY).getTimestamp();
System.out.println(String.format(MESSAGE, value, new Date(value));
Thread.sleep(5000);
// expecting new value
value = cache.retrieveTimestamp(KEY).getTimestamp();
System.out.println(String.format(MESSAGE, value, new Date(value));
SpringApplication.exit(context, () -> 0);
}
}
There are so many details and maybe issues here but first of all you should remove
private long lastRetrieved;
from DummyDao class.
DummyDao is a singleton instance lastRetrieved field is not thread safe.
As you can also see from the logs after you cache the item first time it will always be retrieved from there as it has cached in the first call.
Otherwise you should have seen following log
3000 < 1590064933733 = true
The problem is actually quite simple.
There is no solution to my problem and rightfully so.
The original assumption I had was that "the unless condition is verified every time after the method being annotated is called and the value the method returns is cached (and actually returned) only if the unless condition is not met. Otherwise, the cached value should be returned."
However, this was not the actual behavior because as the documentation states, "#Cacheable is used to demarcate methods that are cacheable - that is, methods for whom the result is stored into the cache so on subsequent invocations (with the same arguments), the value in the cache is returned without having to actually execute the method."
So for a given key, the method will be always executed until the unless condition is not met once. Then the cached value will be returned for all subsequent calls to the method.
So I tried to approach the problem in a different way for my experiment, by trying to use a combination of annotations (#Caching with #Cacheable and #CachePut, although the documentation advises against it).
The value that I was retrieving was always the new one while the one in the cache was always the expected one. (*)
That's when I tilted THAT I couldn't upload the value in the cache based on an internal timestamp that would have been generated in the method that is being cached AND retrieving at the same the cached value if the unless condition was met or the new one otherwise.
What would be the point of executing the method every single time to compute the latest value but returning the cached one (because of the unless condition I was setting)? There is no point...
What I wanted to achieve (update the cache if a period expired) would have been possible if the condition of cacheable was to specify when to retrieve the cached version or retrieve/generate a new one. As far as I am aware, the cacheable is only to specify when a method needs to be cached in the first place.
That is the end of my experiment. The need to test this arose when I came across an issue with an actual production project that used an internal timestamp with this unless condition.
FYI, the most obvious solution to this problem is to use a cache provider that actually provides TTL capabilities.
(*) PS: I also tried few #caching combinations of #CacheEvict (with condition="#root.target.myNewExpiringCheckMethod()==true") and #Cacheable but it failed as well as the CacheEvict enforce the execution of the annotated method.
I'm writing an application that has an instance of a class that contains the esper engine. There are a number of instance variables that I would like to read and set using instance method calls from the EPL in the engine. I don't get any compilation errors and the code runs. But the instance method is not called.
epl statements:
module myModule;
create variable com.tp.main.MyClass myClass;
select myProperty from MyEvent unidirectional, method:myClass.getMyProperty() as myProperty;
A hint could be that if I don't use the method: key word in front of the method call I get an error that myClass.getMyProperty class could not be found. The documentation sometimes uses the method: key word and sometimes not in the examples for calling instance methods from Class-type variables.
I have also tried using the addVariable method in the API with the same results.
code for the method.
public Result getMyProperty() {
Result result = new Result();
result.setResult("propertyValue");
logger.info("This method was called");
return result;
}
The class Result is a POJO with getter and setter for a string.
public class Result {
private String result;
public String getResult() {
return result;
}
public void setResult(String str) {
result = str;
}
}
What am I missing?
You could look at a regression test class. The specific one you may want to look at is ExecFromClauseMethodVariable. Maybe your code does not assign a value to the variable?
Github:
https://github.com/espertechinc/esper/blob/3e396d77308532b202ee452100eaaf9e7a044906/esper-regression/src/test/java/com/espertech/esper/regression/epl/fromclausemethod/ExecFromClauseMethodVariable.java
Problem solved and I thought it might be useful to share the solution. Credit to user650839 who pointed me in the right direction. Here is what ended up fixing the problem.
I reverted back to declaring the variable in the runtime configuration API. I found that I must register the variable class, initialize it with the instance object (this) and finally import the class. Here is the snippet of code that does this configuration in the runtime configuration API.
Configuration configuration = new Configuration();
configuration.addVariable("myClass", com.tp.main.MyClass.class, this);
configuration.addImport(com.tp.main.MyClass.class);
epService = EPServiceProviderManager.getProvider(trade.getTradeName(), configuration);
It seems there is a limitation when declaring the Class variable in the EPL. You cannot initialize it with the instance object you want to use. In the runtime configuration API I was able to initialize it with "this" instance of the object which contains all of the instance variables I want to access from the EPL.
The EPL statement did not change. However, it does seem that you must use the key word method: in front of the method call or you get an error "cannot find class..."
Context:
I am building an Excel document in a generic way with data i receive from a SOAP service endpoint. I receive the data as a List and i have the model (JavaBeans) for every Object i receive according to the method called.
So I set the first row of the sheet as the header from the object's fields (getDeclaredFields).
Then i go on filling up the column row by row with values from the list of objects.
The problem:
I haven't found a workable way of getting the object's field values.
I have tried using the getters with the java reflection API with something like this answer's https://stackoverflow.com/a/5503534/4807777 findGetterName , findGetter however the PropertyDescriptor's getName sometimes is a different letter case from the field name as obtained from the class's getDeclaredFields.
Let's say i overcome this by capitalizing both names, the getReadMethod stil fails - doesn't seem to find getters for the fields which use the is prefix (i.e boolean fields). I don't know if i am misusing it or it is a bug (debugging the getReadMethod appears to only work with the get prefix, even though it appears to handle the is prefix case for booleans).
Considering the fact the fields aren't accesible outside of the object's package, therefore solely through invoking getters.
Is there a better way of obtaining the object's field getters or i am missing something with the getter methods?
Update: Spring's BeanUtils seems to be better for getting the properties with it's getPropertyDescriptors is better than java Class's getDeclaredFields, when the JavaBean properties are mapped to XML elements.
This fixes the different letter cases situation. However it stil doesn't find it's readMethod when not using the get prefix.
Edited - to show an example of getReadMethod not finding the is prefixed getter, as Laszlo Lugosi requested.
A simple class:
class Test {
private String assignmentType;
private Boolean conserved;
public String getAssignmentType() {return assignmentType;}
public void setAssignmentType(String assignmentType) {this.assignmentType = assignmentType;}
public Boolean isConserved() {return conserved;}
public void setConserved(Boolean conserved) {this.conserved = conserved;}
}
Run this with the findGetter and findGetterName written in the answer linked above:
{
Test obj = new Test();
obj.setAssignmentType("someType");
obj.setConserved(true);
Field[] fields = obj.getClass().getDeclaredFields();
String fieldName;
for (int i=0;i<fields.length;i++){
fieldName = fields[i].getName();
java.lang.reflect.Method method;
Object val = null;
try {
method = obj.getClass().getMethod(findGetterName(obj.getClass(),fieldName));
val = method.invoke(obj);
}
catch (Exception e){
e.printStackTrace();
}
}
}
Edited 2
While i could simply write a getReadMethod following the convention Laszlo Lugosi highlighted i do prefer finding an API for handling accessors.
As you know only the object field name, and JavaBean has convention, you can figure out the getters easily. The rules are getUpperfieldname() and isUpperfieldname if field is boolean. And you can find out the return type as well from the object field.
I have written a web-service application that has in a main class generated random value per request (for logging).
I cannot set it as a static field because next request will override it.
I also cannot pass it to the every class that I use in the main one (as an argument or with setter).
Is it possible to create some semi-static field - visible for one request but not for every other that go to the web-service ?
You can safely assume that, in the Java EE model, each single request is served by a single thread and that there is no contention by concurrent requests.
Having said that, you can employ a Singleton using a ThreadLocal, let the Servlet populate the value and have the underlying classes access the sigleton without having notion of the threads or the HTTP request context:
public class RandomValueHolder {
private static ThreadLocal<Long> randomValue;
public static Long getRandomValue() {
return randomValue.get();
}
public static void setRandomValue(Long value) {
randomValue = new ThreadLocal<Long>();
randomValue.set(value);
}
}
Why not use HttpRequest and store the value as attribute
Save the data in the request itself with Request.setAttribute() and use the corresponding Request.getAttribute() to retrieve it.
i was wondering if it's possible to initialize a constant in an interface from a property file using java or using spring messageSource, or such thing is not possible
please advise, thanks.
You can:
public interface Foo {
String a = Properties.getProperty("foo"); // public static final by default
}
However, that means that Properties.getProperty(..) has to be a static method which relies on an already initialized message source (statically again). Depending on the project and the frameworks you use this might not be the best option.
You could initialise a bean via a configuration which includes a final member. Since it's final you can assign to it during construction/initialisation and it then is immutable.
To configure from a property file using Spring, check out the PropertyPlaceholderConfigurer. That will allow you to initialise Spring beans using one or more property files from your classpath, filesystem, remote services etc.
Yes, that's possible:
public static final CONSTANT = System.getProperty("myProperty");
Although it's possible using some static helper method (as was already suggested), I would strongly recommend you not to do so for 2 reasons:
That looks like a pretty bad design. If you need a dynamic value - make it a method in the interface. Or use a static helper directly - you will need one anyway to make it work.
Constants might be inlined at compile time. That shouldn't happen in this particular case - compiler should go with inlining only if it can prove that value won't change between executions, basically if you initialize it with a literal, But there is a tiny chance that it would. Just think how bad will it be - no matter in which environment the progran is running, it picks up some useless value set during compilation, instead of what is configured. (This is rather a theoretical problem, need to say).
by reading a property file like in the example below.
int property1;
String otherProperty;
public void loadProperties(File propFile) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(propFile));
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("Property1=")) {
property1 = Integer.parseInt(line.substring(10));
}
if (line.startsWith("OtherProperty=")) {
otherProperty = line.substring(14);
}
}
}