I have the following classes:
class Parent {
Integer pozition;
}
class Child extends Parent{
Integer pozition;
}
#AllArgsConstructor
class Container {
HashSet<Child> children;
}
and the following code:
private static final Javers JAVERS = JaversBuilder.javers().build();
public static void main(String[] args) {
Child child1 = new Child();
child1.pozition = 0;
((Parent) child1).pozition = 1;
Child child2 = new Child();
child2.pozition = 0;
HashSet<Child> list1 = new HashSet<>();
list1.add(child1);
list1.add(child2);
try {
Diff diff = JAVERS.compare(new Container(list1),new Container(new HashSet<>()));
} catch (Exception e) {
e.printStackTrace();
}
}
I get the exception:
JaversException SNAPSHOT_STATE_VIOLATION: attempt to update snapshot state, property 'pozition' already added
How do I avoid this exception?
Note: this is a self answered question that I made to document an error I came by.
The solution is to remove or rename the pozition field from Child, as the Parent already contains a field with the same name.
Related
Recently I coded an Obfuscator with ASM in Java and wanted to rename classes, methods, and fields. But the problem is, that the code doesn't work it should too, and I have no clue how to fix that. The problem is, that if I obfuscate a jar every method in the class gets renamed, but sometimes (not every time) a bit of code is not getting renamed, so the jar can't be executed. E.g.
public abstract class ColorThread implements Runnable
{
#Getter
private final String name;
#Getter
private Thread thread;
public ColorThread(final String name) {
this.name = name;
Runtime.getRuntime().addShutdownHook(new Thread(this::close));
}
#Override
public void run() {
throw new NotOverriddenException("The Thread \"" + getName() + "\" is not overwritten.");
}
/**
* This method interrupts the running thread.
*/
public void close() {
this.getThread().interrupt();
}
public void start() { //<- Method gets renamed e.g "⢍⢖⣕⠟⡨⠣"
this.thread = new Thread(this, this.getName());
thread.start();
}
}
So this class got obfuscated but later in other code which calls:
final ConnectThread connectThread = new ConnectThread();
connectThread.start(); // <- this line
the line with connectThread.start(); isn't renamed to "connectThread.⢍⢖⣕⠟⡨⠣();". If I use another class which extends ColorThread e.g. ReceiveThread, the start method gets renamed in this bit of code.
I struggled every time with this problem if I made an Obfuscator and because of it I ended the project. But now I want to ask here if someone can help me. Sorry for this long post, but I wanted to give everything needed to see the problem.
The Project is running on Java 1.8.0_161 with ASM-All as a dependency.
To read a jar i use this method. It will store all classes in an ArrayList:
try (final JarFile jarFile = new JarFile(inputFile)) {
final Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
while (jarEntryEnumeration.hasMoreElements()) {
final JarEntry jarEntry = jarEntryEnumeration.nextElement();
if (jarEntry.isDirectory())
continue;
final byte[] bytes = this.readInputStream(jarFile.getInputStream(jarEntry));
if (jarEntry.getName().endsWith(".class")) {
if (jarEntry.getName().endsWith("module-info.class"))
continue;
final ClassNode classNode = new ClassNode();
// new ClassReader(bytes).accept(classNode, ClassReader.EXPAND_FRAMES | ClassReader.SKIP_DEBUG);
new ClassReader(bytes).accept(classNode, ClassReader.EXPAND_FRAMES);
this.classes.add(classNode);
} else {
if (jarEntry.getName().contains("MANIFEST.MF"))
continue;
this.files.put(jarEntry.getName(), bytes);
}
}
this.manifest = jarFile.getManifest();
} catch (final Exception ex) {
ex.printStackTrace();
}
After this i use my transformation system to rename the methods:
#Override
public void transform(final ArrayList<ClassNode> classes, final HashMap<String, byte[]> files) {
final String mainClass = this.getJarResources().getManifest().getMainAttributes().getValue("Main-Class").replace(".", "/");
final HashMap<String, String> methodNames = new HashMap<>();
for (final ClassNode classNode : classes) {
for (final Object methodObj : classNode.methods) {
if (!(methodObj instanceof MethodNode))
continue;
final MethodNode methodNode = (MethodNode) methodObj;
if (methodNode.name.equals("<init>"))
continue;
if (methodNode.name.equals(mainClass) || methodNode.name.equals("main"))
continue;
methodNames.put(classNode.name + "." + methodNode.name + methodNode.desc, this.generateString(6));
}
}
this.remapClasses(classes, methodNames);
}
The remap method looks like this:
public void remapClasses(final ArrayList<ClassNode> classes, final HashMap<String, String> remappedNames) {
final SimpleRemapper simpleRemapper = new SimpleRemapper(remappedNames);
for (int index = 0; index < classes.size(); index++) {
final ClassNode realNode = classes.get(index);
final ClassNode copyNode = new ClassNode();
final ClassRemapper classRemapper = new ClassRemapper(copyNode, simpleRemapper);
realNode.accept(classRemapper);
classes.set(index, copyNode);
}
}
At the end i write the file:
public void writeFile() {
try (final JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(this.outputFile), this.manifest)) {
for (final ClassNode classNode : this.classes) {
final ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
classNode.accept(writer);
jarOutputStream.putNextEntry(new JarEntry(classNode.name + ".class"));
jarOutputStream.write(writer.toByteArray());
jarOutputStream.closeEntry();
}
for (final Map.Entry<String, byte[]> file : this.files.entrySet()) {
final String filePath = file.getKey();
if(filePath.endsWith(".kotlin_module") || filePath.contains("maven") || filePath.contains("3rd-party-licenses"))
continue;
jarOutputStream.putNextEntry(new JarEntry(filePath));
jarOutputStream.write(file.getValue());
jarOutputStream.closeEntry();
}
} catch (final Exception ex) {
ex.printStackTrace();
}
}
[long description warning]
I'm running some cucumber tests which have to be executed intercalated a defined server - for instance:
a.feature -> JBoss Server 1 | b.feature -> JBoss Serv. 2 | c.feature -> JB1 | etc.
For that, I created a hypothetical ExecutorService like this:
final ExecutorService executorService = Executors.newFixedThreadPool(2); //numberOfServers
for (Runnable task : tasks) {
executorService.execute(task);
}
executorService.shutdown();
try {
executorService.awaitTermination(1000, TimeUnit.SECONDS);
} catch (InterruptedException e) {
//doX();
}
The way that I manage about how will be the server chosen as liable to execute is:
inside of my Runnable class created for the executorService, I pass as a parameter a instanceId to a TestNG (XmlTest class) as below:
#Override
public void run() {
setupTest().run();
}
private TestNG setupTest() {
TestNG testNG = new TestNG();
XmlSuite xmlSuite = new XmlSuite();
XmlTest xmlTest = new XmlTest(xmlSuite);
xmlTest.setName(//irrelevant);
xmlTest.addParameter("instanceId", String.valueOf(instanceId));
xmlTest.setXmlClasses(..........);
testNG.setXmlSuites(..........);
return testNG;
}
Then, I get this just fine in a class that extends TestNgCucumberAdaptor:
#BeforeTest
#Parameters({"instanceId"})
public void setInstanceId(#Optional("") String instanceId) {
if (!StringUtils.isEmpty(instanceId)) {
this.instanceId = Integer.valueOf(instanceId);
}
}
And inside a #BeforeClass I'm populating a Pojo with this instanceId and setting the Pojo in a threadLocal attribute of another class. So far, so good.
public class CurrentPojoContext {
private static final ThreadLocal<PojoContext> TEST_CONTEXT = new ThreadLocal<PojoContext>();
...
public static PojoContext getContext(){
TEST_CONTEXT.get();
}
Now the problem really starts - I'm using Guice (Cucumber guice as well) in a 3rd class, injecting this pojo object that contains the instanceId. The example follows:
public class Environment {
protected final PojoContext pojoContext;
#Inject
public Environment() {
this.pojoContext = CurrentPojoContext.getContext();
}
public void foo() {
print(pojoContext.instanceId); // output: 1
Another.doSomething(pojoContext);
}
class Another{
public String doSomething(PojoContext p){
print(p.instanceId); // output: 2
}
}
}
Here it is not every time like this the outputs (1 and 2) but from time to time, I realized that the execution of different threads is messing with the attribute pojoContext. I know that is a little confusing, but my guess is that the Guice Injector is not thread-safe for this scenario - it might be a long shot, but I'd appreciate if someone else takes a guess.
Regards
Well, just in order to provide a solution for someone else, my solution was the following:
Create a class that maintains a Map with an identifier (unique and thread-safe one) as the key and a Guice Injector as value;
Inside my instantiation of Guice injector, I created my own module
Guice.createInjector(Stage.PRODUCTION, MyOwnModules.SCENARIO, new RandomModule());
and for this module:
public class MyOwnModules {
public static final Module SCENARIO = new ScenarioModule(MyOwnCucumberScopes.SCENARIO);
}
the scope defined here provides the following:
public class MyOwnCucumberScopes {
public static final ScenarioScope SCENARIO = new ParallelScenarioScope();
}
To sum up, the thread-safe will be in the ParallelScenarioScope:
public class ParallelScenarioScope implements ScenarioScope {
private static final Logger LOGGER = Logger.getLogger(ParallelScenarioScope.class);
private final ThreadLocal<Map<Key<?>, Object>> threadLocalMap = new ThreadLocal<Map<Key<?>, Object>>();
#Override
public <T> Provider<T> scope(final Key<T> key, final Provider<T> unscoped) {
return new Provider<T>() {
public T get() {
Map<Key<?>, Object> scopedObjects = getScopedObjectMap(key);
#SuppressWarnings("unchecked")
T current = (T) scopedObjects.get(key);
if (current == null && !scopedObjects.containsKey(key)) {
current = unscoped.get();
scopedObjects.put(key, current);
}
return current;
}
};
}
protected <T> Map<Key<?>, Object> getScopedObjectMap(Key<T> key) {
Map<Key<?>, Object> map = threadLocalMap.get();
if (map == null) {
throw new OutOfScopeException("Cannot access " + key + " outside of a scoping block");
}
return map;
}
#Override
public void enterScope() {
checkState(threadLocalMap.get() == null, "A scoping block is already in progress");
threadLocalMap.set(new ConcurrentHashMap<Key<?>, Object>());
}
#Override
public void exitScope() {
checkState(threadLocalMap.get() != null, "No scoping block in progress");
threadLocalMap.remove();
}
private void checkState(boolean expression, String errorMessage) {
if (!expression) {
LOGGER.info("M=checkState, Will throw exception: " + errorMessage);
throw new IllegalStateException(errorMessage);
}
}
}
Now the gotcha is just to be careful regarding the #ScenarioScoped and the code will work as expected.
I'm trying to find a nice way to add a prefix to my logs without passing it on every calls, without instanciate Logger again.
The purpose is to trace Rest calls individually.
(The prefix would be re-generated on each call using UUID)
This would be like
#RestController
class MyClass {
//Here the prefix is initialise once
//default value is X
Logger LOG = LoggerFactory.getLogger(MyClass.class);
#RequestMapping("/a")
void methodA() {
LOG.debug("foo");
}
#RequestMapping("/b")
void methodB() {
LOG.setPrefix("B");
LOG.debug("bar");
}
with this output
[...] [prefix X] foo
[...] [prefix B] bar
As you've said you're using Logback, here's a couple options to do the kind of thing you're trying to do:
Markers
Each log entry can have a "marker" established for it. (The best documentation I've seen for it is in the SLF4J FAQ.) Something like:
class MyClass {
Marker methodBMarker = MarkerFactory.getMarker("B");
Logger logger = LoggerFactory.getLogger(MyClass.class);
…
void methodB() {
logger.debug(methodBMarker, "bar");
}
}
You would need to update all log entries in each method to use the appropriate marker. You can then put %marker in your layout to put the log entry's marker into the log.
MDC
The other option is to use the "Mapped Diagnostic Context" functionality to specify the current "context" for each log entry.
class MyClass {
Logger logger = LoggerFactory.getLogger(MyClass.class);
…
void methodB() {
MDC.put("method", "b");
try {
…
logger.debug("bar");
…
} finally {
MDC.clear();
}
}
}
You would then use %mdc{method} in your layout to output that particular MDC value. Note that MDC is really intended to be used for per-thread values like something web-connection-specific, so it's important to ensure that it's cleared out of what you don't want when you're leaving the context you want the value logged in.
Please see http://www.slf4j.org/extensions.html#event_logger for an example of how to use the MDC. You do not have to use the EventLogger. Once you set things in the MDC they are present in every log record.
A Marker does not meet your criteria since it has to be specified on every call.
Here's my MDC implementation explained to share my experiments with MDC.
//In this abstract class i'm defining initLogData methods to set MDC context
//It would be inherited by Controller and other classes who needs logging with traced transactions
public abstract class AbstractService {
protected LogData initLogData() {
return LogData.init();
}
protected LogData initLogData(String tName) {
return LogData.init(tName);
}
}
//LogData holds the MDC logic
public class LogData {
private final static int nRandom = 8;
//this keys are defined in logback pattern (see below)
private final static String tIdKey = "TID";
private final static String tNameKey = "TNAME";
//Transaction id
private String tId;
//Transaction name
private String tName;
public String getTId() {
return tId;
}
public void setTId(String tId) {
this.tId = tId;
}
public String gettName() {
return tName;
}
public void settName(String tName) {
this.tName = tName;
}
//random transaction id
//I'm not using uuid since its too longs and perfect unicity is not critical here
public String createTId(){
Random r = new Random();
StringBuilder sb = new StringBuilder();
while(sb.length() < nRandom){
sb.append(Integer.toHexString(r.nextInt()));
}
return sb.toString().substring(0, nRandom);
}
//private constructors (use init() methods to set LogData)
private LogData(String tId, String tName) {
this.tId = tId;
this.tName = tName;
}
private LogData(String tName) {
this.tId = createTId();
this.tName = tName;
}
private LogData() {
this.tId = createTId();
}
//init MDC with cascading calls processing (using same id/name within same context
//even if init() is called again)
public static LogData init(String tName) {
String previousTId = MDC.get(tIdKey);
String previousTName = MDC.get(tNameKey);
MDC.clear();
LogData logData = null;
if(previousTId != null) {
logData = new LogData(previousTId, previousTName);
} else {
logData = new LogData(tName);
}
MDC.put(tIdKey, logData.getTId());
MDC.put(tNameKey, logData.gettName());
return logData;
}
//init MDC without cascading calls management (new keys are generated for each init() call)
public static LogData init() {
MDC.clear();
LogData logData = new LogData();
MDC.put(tIdKey, logData.getTId());
return logData;
}
}
//logback.xml : values to include in log pattern
[%X{TID}] [%X{TNAME}]
#RestController
#RequestMapping("/test")
public class RestControllerTest extends AbstractRestService {
private final Logger LOG = LoggerFactory.getLogger(ServiceRestEntrypointStatus.class);
#RequestMapping(value="/testA")
public void testA() {
initLogData("testA");
LOG.debug("This is A");
}
#RequestMapping(value="/testB")
public void testB() {
initLogData("testA");
LOG.debug("This is B");
}
#RequestMapping(value="/testC")
public void testC() {
initLogData("testC");
LOG.debug("This is C");
testA();
testB();
}
}
Calling RestControllerTest mapped /test/testA produces :
[fdb5d310] [testA] This is A
Calling /test/testC produces (id and name are kept even if initLogData is called in sub methods):
[c7b0af53] [testC] This is C
[c7b0af53] [testC] This is A
[c7b0af53] [testC] This is B
I have a set of node id's (Set< Long >) and want to restrict or filter the results of an query to only the nodes in this set. Is there a performant way to do this?
Set<Node> query(final GraphDatabaseService graphDb, final Set<Long> nodeSet) {
final Index<Node> searchIndex = graphdb.index().forNodes("search");
final IndexHits<Node> hits = searchIndex.query(new QueryContext("value*"));
// what now to return only index hits that are in the given Set of Node's?
}
Wouldn't be faster the other way round? If you get the nodes from your set and compare the property to the value you are looking for?
for (Iterator it=nodeSet.iterator();it.hasNext();) {
Node n=db.getNodeById(it.next());
if (!n.getProperty("value","").equals("foo")) it.remove();
}
or for your suggestion
Set<Node> query(final GraphDatabaseService graphDb, final Set<Long> nodeSet) {
final Index<Node> searchIndex = graphdb.index().forNodes("search");
final IndexHits<Node> hits = searchIndex.query(new QueryContext("value*"));
Set<Node> result=new HashSet<>();
for (Node n : hits) {
if (nodeSet.contains(n.getId())) result.add(n);
}
return result;
}
So the fastest solution I found was directly using lucenes IndexSearcher on the index created by neo4j and use an custom Filter to restrict the search to specific nodes.
Just open the neo4j index folder "{neo4j-database-folder}/index/lucene/node/{index-name}" with the lucene IndexReader. Make sure to use not add a lucene dependency to your project in another version than the one neo4j uses, which currently is lucene 3.6.2!
here's my lucene Filter implementation that filters all query results by the given Set of document id's. (Lucene Document id's (Integer) ARE NOT Neo4j Node id's (Long)!)
import java.io.IOException;
import java.util.PriorityQueue;
import java.util.Set;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.search.Filter;
public class DocIdFilter extends Filter {
public class FilteredDocIdSetIterator extends DocIdSetIterator {
private final PriorityQueue<Integer> filterQueue;
private int docId;
public FilteredDocIdSetIterator(final Set<Integer> filterSet) {
this(new PriorityQueue<Integer>(filterSet));
}
public FilteredDocIdSetIterator(final PriorityQueue<Integer> filterQueue) {
this.filterQueue = filterQueue;
}
#Override
public int docID() {
return this.docId;
}
#Override
public int nextDoc() throws IOException {
if (this.filterQueue.isEmpty()) {
this.docId = NO_MORE_DOCS;
} else {
this.docId = this.filterQueue.poll();
}
return this.docId;
}
#Override
public int advance(final int target) throws IOException {
while ((this.docId = this.nextDoc()) < target)
;
return this.docId;
}
}
private final PriorityQueue<Integer> filterQueue;
public DocIdFilter(final Set<Integer> filterSet) {
super();
this.filterQueue = new PriorityQueue<Integer>(filterSet);
}
private static final long serialVersionUID = -865683019349988312L;
#Override
public DocIdSet getDocIdSet(final IndexReader reader) throws IOException {
return new DocIdSet() {
#Override
public DocIdSetIterator iterator() throws IOException {
return new FilteredDocIdSetIterator(DocIdFilter.this.filterQueue);
}
};
}
}
To map the set of neo4j node id's (the query result should be filtered with) to the correct lucene document id's i created an inmemory bidirectional map:
public static HashBiMap<Integer, Long> generateDocIdToNodeIdMap(final IndexReader indexReader)
throws LuceneIndexException {
final HashBiMap<Integer, Long> result = HashBiMap.create(indexReader.numDocs());
for (int i = 0; i < indexReader.maxDoc(); i++) {
if (indexReader.isDeleted(i)) {
continue;
}
final Document doc;
try {
doc = indexReader.document(i, new FieldSelector() {
private static final long serialVersionUID = 5853247619312916012L;
#Override
public FieldSelectorResult accept(final String fieldName) {
if ("_id_".equals(fieldName)) {
return FieldSelectorResult.LOAD_AND_BREAK;
} else {
return FieldSelectorResult.NO_LOAD;
}
}
};
);
} catch (final IOException e) {
throw new LuceneIndexException(indexReader.directory(), "could not read document with ID: '" + i
+ "' from index.", e);
}
final Long nodeId;
try {
nodeId = Long.valueOf(doc.get("_id_"));
} catch (final NumberFormatException e) {
throw new LuceneIndexException(indexReader.directory(),
"could not parse node ID value from document ID: '" + i + "'", e);
}
result.put(i, nodeId);
}
return result;
}
I'm using the Google Guava Library that provides an bidirectional map and the initialization of collections with an specific size.
I have a project using JSF primefaces and EJB managed Beans with hibernate storage.
http://www.primefaces.org/showcase/ui/treeAjax.jsf
Question: I keep on getting a out of memory or stack overflow errors can you see a problem with my recursion?
#ManagedBean(name = "categoryController")
#RequestScoped
public class CategoryController implements Serializable {
...
#EJB
private CategoryFacade ejbFacade;
private TreeNode root;
public TreeNode getRoot() {
return root;
}
#PostConstruct
public void init() {
root = new DefaultTreeNode("Root", null);
System.out.print("Facade value=" + getFacade());
Category categoryRoot = getFacade().find(new Integer(1));
getSubcategories(categoryRoot, root);
}
private void getSubcategories(Category categoryRoot, TreeNode root) {
List<Category> list = getFacade().findByNamedQuery("Category.findByPCatid", "pcatid", categoryRoot);
Iterator<Category> it = list.iterator();
while (it.hasNext()) {
Category subcategory = it.next();
TreeNode nextNode = new DefaultTreeNode(subcategory.getUcatid(), root);
getSubcategories(subcategory, nextNode);
}
}
...
}
The problem is that your recursion is in an infinite loop on your root element.
try adding this:
if (!subcategory.getCatid().equals(new Integer(1))) {
getSubcategories(subcategory, nextNode);
}
You can also look up the Primefaces event listeners to generate the tree on demand.
http://www.primefaces.org/showcase/ui/treeEvents.jsf